FZU 1969 GCD Extreme UESTC 1723 吴神的大脑
Accept: 77 Submit: 136
Time Limit: 1000 mSec Memory Limit : 32768 KB
Problem Description
Given the value of N, you will have to find the value of G. The meaning of G is given in the following code
G=0;
for(i=1;i<N;i++)
for(j=i+1;j<=N;j++)
G+=gcd(i,j);
/*Here gcd() is a function that finds the greatest common divisor of the two input numbers*/
Input
The input file contains at most 20000 lines of inputs. Each line contains an integer N (1<N <1000001). The meaning of N is given in the problem statement. Input is terminated by a line containing a single zero.
Output
For each line of input produce one line of output. This line contains the value of G for the corresponding N. The value of G will fit in a 64-bit signed integer.
Sample Input
10 100 200000 0
Sample Output
67 13015 143295493160
参考思想
http://hi.baidu.com/aekdycoin/item/8095ba4eebb2d3eba5c066d2
代码参考
http://blog.csdn.net/duanxian0621/article/details/7847514
G=0; for(k=1;k< N;k++) for(j=i+1;j<=N;j++) { G+=gcd(k,j); } 显然如果O(n^2*gcd复杂度) ,一组数据就够你挂的了. 因此我们必须优化优化再优化 观察显然可以得到: G= gcd(1,2)+ gcd(1,3)+gcd(2,3)+ gcd(1,4)+gcd(2,4)+gcd(3,4)+ ............................................................. gcd(1,n)+gcd(2,n)+............................+gcd(n-1,n) 于是得到G的公式为什么写成这种形式?是为了求解方便 显然如果依然暴力套肯定还是超时 于是我们考虑优化,因为这个公式还是很有特点的 如果我们可以很快的得到下面的值(假设是G(n)),那么上面的公式通过预处理来得到解答,最后查询只需要O(1)
这个如何计算? 由于gcd(n,i) | n 所以gcd(n,i)=k,k|n 于是我们可以先得到n的所有因子,然后利用gcd(n,i)=k--->gcd(n/k,i/k)=1来求解 即先求出满足gcd(n,i)=k的个数(Euler(n/k)),然后把个数直接乘上k就是这一部分的和,同理其他部分 显然如果暴力分解肯定超时,于是考虑预处理 1.预处理出1..1000000的Euler() 2.预处理出1..1000000的G(n) 3.预处理区间和 然后就可以了 预处理Euler()并不难,详见: http://hi.baidu.com/aekdycoin/blog/item/7055063fa5011a3a70cf6c30.html 至于处理G(n),必须使用到预处理因子和的类似技巧. 预处理因子和只需要用2个循环搞定(前提是规模不大,百万级别还是可以接受的) 第1个循环,i,枚举1..sqrt(N) 第2个循环,j,枚举j=k*i,在保证i*i<j的情况下,我们根据因子对称性可以知道 dp[j]+=i+j/i;考虑到i*i=j的情况下我们只需要加一次,所以这时候dp[j]+=i; 而类似的,这题也可以这么做,假设i为j的因子,那么显然有 1.i*i<j G[j]+=Euler(i)*(j/i)+Euler(j/i)*i 2.i*i==j G[j]+=Euler(i)*i
学到了快速同时求很多欧拉函数的方法
//还有利用欧拉函数求求1-n中所有数的最大公约数之和)
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #define lson l,m,k<<1 #define rson m+1,r,k<<1|1 #define N 1000001 using namespace std; __int64 phi[N]; __int64 ans[N]; void init() { int i,j,k; for(i=2;i<N;i++) phi[i]=i; for(i=2;i<N;i++) if(phi[i]==i) for(j=i;j<N;j+=i) phi[j]=phi[j]/i*(i-1); for(i=2;i<N;i++) ans[i]=phi[i]; for(i=2;i<=1000;i++) { ans[i*i]+=phi[i]*i; for(j=i*i+i,k=i+1;j<N;j+=i,k++) ans[j]+=phi[k]*i+k*phi[i]; } for(i=3;i<N;i++) ans[i]+=ans[i-1]; } int main() { init(); int n; while(scanf("%d",&n),n) { printf("%I64d\n",ans[n]); } return 0; }