题意:给你一个数N,求N以内和N的最大公约数的和
解题思路:
一开始直接想暴力做,4000000的数据量肯定超时。之后学习了一些新的操作。
题目中所要我们求的是N内gcd之和,设s[n]=s[n-1]+gcd(1,n)+gcd(2,n)+gcd(3,n)+gcd(4,n).......
再设f[n]=gcd(1,n)+gcd(2,n)+gcd(3,n)+gcd(4,n).......;
思考一下,假设gcd(x,n)=ans,ans便是x和n的最大公约数,那么有几个ans我们将某ans的个数sum(num*ans)是不是就是当前f[n]的值;
那么某个ans的个数num我们该怎么求???
gcd(x,n)=ans;那么gcd(x/ans,n/ans)就是1;就是说x/ans和n/ans是互素的,那么求n以内和n互素的数的个数我们怎么办???就用欧拉函数phi;
其个数就是phi[n/ans];
然后,,,,你以为求这点就做完了是吗??玩笑,,,;
你可以直接打出4000 000欧拉表,那么我们该怎么遍历赋值f[n];f[n]=num*ans;我们遍历n在遍历ans么??这个不现实,在当前这个n中会有部分ans白白计算
所以我们最好的办法就是先行枚举ans,我们知道,当前ans所对应的n一定是ans的倍数,所以我们遍历n极为方便,只需要令n=2*ans,3*ans,4*ans,5*ans......
这里有个点就是n不能是ans,所以我们第二重循环里就应该从2*ans开始;这个地方一会在代码中点出;
具体就是这么多;
AC代码
1 #include<stack> 2 #include<queue> 3 #include<cmath> 4 #include<cstdio> 5 #include<cstring> 6 #include<iostream> 7 #include<algorithm> 8 9 using namespace std; 10 11 #define INF 0x3f3f3f3f 12 typedef long long ll; 13 const ll maxn = 4000005; 14 ll n; 15 16 ll euler[maxn]; 17 ll fun_[maxn]; 18 19 void euler_(ll maxn) 20 { 21 for (int i=1;i<=maxn;i++) 22 { 23 euler[i]=i; 24 } 25 for (int i=2;i<maxn;i++) 26 { 27 if (euler[i]==i) 28 { 29 for (int j=i;j<maxn;j+=i) 30 { 31 euler[j]=euler[j]/i*(i-1); 32 // cout<<euler[j]<<endl; 33 } 34 } 35 } 36 } 37 38 ll s[maxn]; 39 40 41 int main() 42 { 43 euler_(maxn); 44 //memset(fun_,0,sizeof(fun_)); 45 for (int i=1;i<=maxn;i++) 46 { 47 for (int j=i+i;j<=maxn;j+=i) 48 { 49 //cout<<i<<" "<<n/i<<" "<<euler[n/i]<<endl; 50 51 fun_[j]+=i*euler[j/i]; 52 //cout<<fun_[j]<<endl; 53 } 54 } 55 s[1]=0; 56 57 for (int i=2;i<=maxn;i++) 58 { 59 s[i]=s[i-1]+fun_[i]; 60 //cout<<i<<" "<<s[i]<<endl; 61 }//cout<<"***********"<<endl; 62 while (cin>>n&&n) 63 { 64 //cout<<n<<endl; 65 cout<<s[n]<<endl; 66 } 67 }