[BZOJ3309]DZY Loves Math(莫比乌斯反演+线性筛)
$\sum\limits_{T=1}^{n}\lfloor\frac{n}{T}\rfloor\lfloor\frac{m}{T}\rfloor\sum\limits_{d|T}f(d)\mu(\frac{T}{d})$
求出$g(n)=\sum_{d|T}f(d)\mu(\frac{n}{d})$的前缀和,分块加速。
考虑怎么快速求g。观察什么时候d能对答案产生贡献,显然当且仅当:对于n的每个质因子,d包含这个质因子的次幂数至多比n包含这个质因子的次幂数少1,否则n/d就会包含平方因子。
接下来分两种情况考虑(显然若n只包含一个质因子则g(n)=1):
1) n中存在两个质因子次数不同。
那么考虑所有次数的最大值,设为k。当我们确定n中次数为k的那些因子的选取情况时(这里选取是指是否d包含这个因子的次数比n少1),剩下的数若选取个数为奇数则$\mu$为-1否则为1。考虑到组合数的性质,n个数中选取奇数个的方案数与选取偶数个相同,所以这种情况整个的贡献为0。
2) n中所有质因子次数相同
与上面不同的是,这里已经不存在次数小于k的因子了。那么,这些质因子的选取情况与$\mu$的乘积同样由于上面那个组合数的性质,使和为0。但有一个数不同,就是当d包含的所有因子的次数都比n少1时,f(d)为k-1而不是k。综上这部分的g(n)=(-1)^(质因子个数+1)。
考虑线性筛求g。分别记录每个数最小因子的次数,最小因子的乘积,转移显然。
1 #include<cstdio> 2 #include<algorithm> 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 4 typedef long long ll; 5 using namespace std; 6 7 const int N=10000010; 8 int T,n,m,tot,b[N],p[N]; 9 ll g[N],f[N],h[N]; 10 11 void init(int n){ 12 rep(i,2,n){ 13 if (!b[i]) p[++tot]=i,h[i]=1,f[i]=i,g[i]=1; 14 for (int j=1; j<=tot && p[j]*i<=n; j++){ 15 int t=p[j]*i; b[t]=1; 16 if (i%p[j]==0){ 17 h[t]=h[i]+1; f[t]=f[i]*p[j]; 18 int s=t/f[t]; 19 if (s==1) g[t]=1; else g[t]=(h[s]==h[t]) ? -g[s] : 0; 20 }else h[t]=1,f[t]=p[j],g[t]=(h[i]==1) ? -g[i] : 0; 21 } 22 } 23 rep(i,1,n) g[i]+=g[i-1]; 24 } 25 26 ll solve(){ 27 if (n>m) swap(n,m); ll res=0; 28 for (int i=1,lst; i<=n; i=lst+1) 29 lst=min(n/(n/i),m/(m/i)),res+=1ll*(n/i)*(m/i)*(g[lst]-g[i-1]); 30 return res; 31 } 32 33 int main(){ 34 freopen("bzoj3309.in","r",stdin); 35 freopen("bzoj3309.out","w",stdout); 36 init(10000000); 37 for (scanf("%d",&T); T--; ) 38 scanf("%d%d",&n,&m),printf("%lld\n",solve()); 39 return 0; 40 }