【传送门:BZOJ2705】
简要题意:
给出一个n,输出Σgcd(i,n)(1<=i<=n)
题解:
首先数据范围惊人,然后要加long long!!
怎么做呢?
就是先求出n的所有因数
设a[i]表示n的第i个因子,f[i]为以第i个因子为最大公约数的个数
然后一般情况下f[i]应该是n/i
但是我们先来看数据:
6的因子为:1,2,3,6
那么f[6]=1是无可非议的
但是f[3]并不等于2,而是等于1,为什么?
因为f[6]中已经计算了6,而f[3]中也把6也算了进去,显然是不对的
那么我们就从后往前求f数组,然后先将f[i]=n/a[i],然后往后面找是否有a[j]%a[i]==0(1<=i<j<=n),如果有,则f[i]-=f[j]
就好像容斥一样做就可以了
注意得出来的∑f[i]并不是最终答案,∑f[i]*a[i]才是要的答案
参考代码:
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<cstdlib> using namespace std; typedef long long LL; LL a[11000]; LL f[11000]; int main() { LL n; scanf("%lld",&n); LL t=int(double(sqrt(n+1))); int len=0; memset(f,0,sizeof(f)); for(LL i=1;i<=t;i++) { if(n%i==0) { a[++len]=i; if(i*i!=n) a[++len]=n/i; } } f[len]=1; sort(a+1,a+len+1);LL ans=a[len]; for(int i=len-1;i>=1;i--) { f[i]=n/a[i]; for(int j=len;j>i;j--) { if(a[j]%a[i]==0) { f[i]-=f[j]; } } ans+=f[i]*a[i]; } printf("%lld\n",ans); return 0; }