BZOJ3309 DZY Loves Math(莫比乌斯反演+线性筛)
一通正常的莫比乌斯反演后,我们只需要求出g(n)=Σf(d)*μ(n/d)的前缀和就好了。
考虑怎么求g(n)。当然是打表啊。设n=∏piai,n/d=∏pibi 。显然若存在bi>1则这个d没有贡献。考虑bi为0和1两种情况。如果只看ai最小的质因子的选取情况,会发现大部分情况下其是0还是1,对f的取值是没有影响的,但会使μ取反,于是就抵消为0。而特殊情况即为所有ai均相同,此时若所有bi都取1会使f减少。与一般情况比较可以得到此时g(n)=(-1)质因子个数+1。
然后就可以线性筛了。记录一下n去掉最小质因子后的数及最小质因子的幂次就可以了。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define N 10000010 int T,prime[N],f[N],p[N],c[N],v[N],cnt=0; bool flag[N]; int main() { #ifndef ONLINE_JUDGE freopen("bzoj3309.in","r",stdin); freopen("bzoj3309.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif T=read(); flag[1]=1;p[1]=1;c[1]=0;f[1]=0; for (int i=2;i<=N-10;i++) { if (!flag[i]) prime[++cnt]=i,p[i]=1,c[i]=1,f[i]=1; for (int j=1;j<=cnt&&prime[j]*i<=N-10;j++) { int t=prime[j]*i; flag[t]=1; if (i%prime[j]==0) { p[t]=p[i]; c[t]=c[i]+1; if (c[p[i]]==0) f[t]=1; else f[t]=(c[t]==c[p[i]]?-f[p[i]]:0); break; } p[t]=i; c[t]=1; if (c[i]==0) f[t]=1; else f[t]=(c[i]==1?-f[i]:0); } } for (int i=1;i<=N-10;i++) f[i]+=f[i-1]; while (T--) { int n=read(),m=read(); long long ans=0; for (int i=1;i<=min(n,m);i++) { int t=min(n/(n/i),m/(m/i)); ans+=1ll*(f[t]-f[i-1])*(n/i)*(m/i); i=t; } printf(LL,ans); } return 0; }