题目链接
HYSBZ-2818
思路
这道题思路略微复杂,主要是需要交换枚举对象。
首先明确我们要求的答案
按照套路来
设f(n)为gcd(a,b)=n的个数
则F(n)为gcd(a,b)=n及n的倍数的个数
然后可以转化为
然后用莫比乌斯倍数反演
然后代入得到
然后我们交换枚举项,我们枚举
这时候我们枚举T=pt(T是中间变量,跟上面那个没有关系),只需要枚举到Min(n,m)
这一步可能很难理解,后面一部分,其实前面是倍数,那么相当于提取公因式后,乘上的数就变成因数了。
这个式子就是我们最终得到的式子了,后面的明显可以预处理出来,因为T确定了,后面的和式也就确定了
前面一部分我们可以用分块除法解决。
这题不要单独打表,会T。把get_mu放入while中即可,单组数据
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| #include<iostream> #include<cstdio> #include<cstring> #include<assert.h> using namespace std; #define ll long long const int maxnx = 1e7+10; int mu[maxnx]; int sum[maxnx]; bool vis[maxnx]; int g[maxnx]; int prime[maxnx],cnt; void get_mu(int maxn) { mu[1]=1; for(int i=2;i<maxn;i++) { if(!vis[i]) { prime[cnt++]=i; mu[i]=-1; } for(int j=0;j<cnt&&prime[j]*i<maxn;j++) { vis[i*prime[j]]=true; if(i%prime[j]) { mu[i*prime[j]]=-mu[i]; } else { mu[i*prime[j]]=0; break; } } } for(int j=0;j<cnt;j++) { for(int i=1;i*prime[j]<maxn;i++) { g[i*prime[j]]+=mu[i]; } } for(int i=1;i<maxn;i++)sum[i]=sum[i-1]+g[i]; } int main() { ll n; while(scanf("%lld",&n)!=EOF) { ll ans = 0; get_mu(n); for(int i=1,last;i<=n;i=last+1) { last=n/(n/i); ans+=1ll*(sum[last]-sum[i-1])*(n/i)*(n/i); } cout<<ans<<endl; } }
|
你最愿意做的哪件事,才是你的天赋所在