1. 程式人生 > >2018京東校招筆試題-資料分析崗

2018京東校招筆試題-資料分析崗

題目大意是給出一個數字n,問a^b=c^d(1<=a、b、c、d<=n)這種式子的個數 1^2=1^1 1^1=1^2,這樣的算兩個,n<=100000.

首先分析題目,n的資料範圍肯定是不能暴力的,從其他同學的反饋也表示這題暴力只能過20%

此題的規律在於,以一個較小的數字a當基底 將 a^p 和 a^q(設為m,n)當做新的底來計算m^c=n^d(m、n<=n),才能避免重複和漏判

比如4(2^2)和8(2^3),此時需要計算2和3的最小公倍數,然後再計算在冪指數不超過n的情況下滿足4^c=8^d的式子的個數

比如從2^k開始,分別計算底為2^k和(2^(k+1)一直到2^s(2^s<=n&&s>=k+1))的式子,同時要將2^k置為已訪問過,防止重複計算(2^k<=n)

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <queue>
#include <algorithm>
#define LL long long
using namespace std;
const LL p = 1e9+7;
LL gcd(LL a,LL b){
    LL m=a,n=b,c;
    while(b!=0){
        c=a%b; a=b;  b=c;
    }
    LL sum=m*n/a;
    return sum;
}
LL mizhishu(LL n,LL k){
    LL sum=1;
    for(LL i =0;i<k;i++){
        sum*=n;
    }
    return sum;
}
LL n;
LL ans=0;
LL hash_n[101000];
int main(){
    cin>>n;
    memset(hash_n,0,sizeof(hash_n));
    if(n==1){
        cout<<1<<endl;
        return 0;
    }
    LL k;
    LL k1;
    LL k2;
    LL sum;
    ans=0;
    ans+=(n*n)%p;
    ans%=p;
    //cout<<ans<<endl;
    for(LL i=2;i<=n;i++){
        ans+=n;
        ans%=p;
        if(hash_n[i]==0){
            k=1;
            while(mizhishu(i,k)<=n){
            //cout<<mizhishu(i,k)<<endl;
            //ans+=2*(n/k);
                hash_n[mizhishu(i,k)]=1;
                k1 = k+1;
                while(k1<=n&&mizhishu(i,k1)<=n){
                        sum = gcd(k,k1);
                        //cout<<"i:"<<i<<" k: "<<k<<" k1: "<<k1<<" sum:"<<sum<<endl;
                        ans+=2*(n*k/(sum));
                        ans%=p;
                        k1++;
                    }
                ans%=p;
                k++;
            }
        }
    }
    ans%=p;
    cout<<ans<<endl;
    return 0;
}