#include<bits/stdc++.h> usingnamespace std; typedeflonglong ll; constint N = 2e6+6; bool vis[N]; int mobius[N], summob[N]; int prime[N]; int n, primecnt; voidinit(){ mobius[1] = 1; vis[1] = 1; for(int i=2;i<=n;i++){ if(!vis[i]) vis[i] = 1, prime[++primecnt] = i, mobius[i] = -1; for(int j=1;j<=primecnt && prime[j] * i <= n; j++){ vis[prime[j] * i] = 1; mobius[prime[j] * i] = (i % prime[j] ? -mobius[i]: 0); if(i % prime[j] == 0) break; } } for(int i=1;i<=n;i++) summob[i] = summob[i-1] + mobius[i]; }
ll solve(int lim){ int l = 0, r = 0; ll ans = 0; while(r < lim){ l = r + 1; r = lim/(lim/l); ans += 1ll*(lim/l)*(lim/l)*(summob[r]-summob[l-1]); } return ans; } intmain(){ ios::sync_with_stdio(0); cin.tie(0), cout.tie(0); cin>>n; init(); ll ans = 0; for(int i=1;i<=n;i++){ ans += i * solve(n/i); } ans -= 1ll*(n+1)*n/2; ans /= 2; cout<<ans; return0; }
版本(只需更改主函数即可):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
intmain(){ ios::sync_with_stdio(0); cin.tie(0), cout.tie(0); cin>>n; init(); ll ans = 0; int l = 0, r = 0; while(r < n){ l = r+1; r = n/(n/l); ans += 1ll * (l+r)*(r-l+1)/2 * solve(n/l); } ans -= 1ll*(n+1)*n/2; ans /= 2; cout<<ans<<'\n'; return0; }
其变种:
题目描述:
给定 ,求
其中 表示 和 的最大公约数,。多测, 组数据,。
一样,先将其推到
然后利用整除分块做。不过,这里的整除分块要稍微做个小改动,一段区间是 :
1 2 3 4 5 6 7 8 9 10 11
longlongsolve(int x, int y){ if(x<y) swap(x, y); int l = 0, r = 0; longlong ans = 0; while(r < y){ l = r + 1; r = min(x/(x/l), y/(y/l)); ans += 1ll * (summob[r] - summob[l-1]) * (x/l) * (y/l); } return ans; }