Online Judge | Problem Set | Authors | Online Contests | User | ||||||
---|---|---|---|---|---|---|---|---|---|---|
Web Board Home Page F.A.Qs Statistical Charts | Current Contest Past Contests Scheduled Contests Award Contest |
懂点数学还是很重要的(另一种题解,不用算Euler函数)附十几年前的AC代码题目不用多说,算F(n):=sum_(m=2..n)phi(m) 算phi是个麻烦活:无论如何算phi(n)都需要对n做因式分解(或者用筛法优化) 所以,有没有办法不算这个东西? 有。 F(n)本质上是集合{1<=a<b<=n:gcd(a,b)=1}的大小。 可以想到,把整个集合{1<=a<b<=n}按照gcd(a,b)的值分类。 集合{1<=a<b<=n:gcd(a,b)=m}的大小当然是F(n/m),于是得到递推关系 sum_{m=1..n-1} F(n/m)=n(n-1)/2,或者写成 F(n)=n(n-1)/2-sum_{m=2..n-1}F(n/m) m大(m>sqrt(n))的时候,n/m的值当然会有重复;所以进一步写成 F(n)=n(n-1)/2-sum_{m=2..sqrt(n)}F(n/m)+F(m)(n/m-n/(m+1)) 剩下的就是对于n较小时候的F(n)随算随存以免递归爆炸了 代码: __int64 ph[70000]={0,0,1}; /* 预存的范围,70000是试验出来的; */ __int64 f(int n){ int m; __int64 s=0,v=(__int64)n; /* 需要int64,否则n*n会溢出 */ if((n<70000)&&ph[n]) return ph[n]; for(m=2;m<n/m;m++){ s+=f(n/m);s+=f(m)*(n/m-n/(m+1)); } if(m==n/m)s+=f(m); s=(v*v-v)/2-s; if(n<70000) ph[n]=s; return s; } main(n){while(scanf("%d",&n),n)printf("%I64d\n",f(n));} 756K 94MS C 275B Followed by: Post your reply here: |
All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator