BZOJ3994: [SDOI2015]约数个数和
3994: [SDOI2015]约数个数和
Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 1072 Solved: 736
[Submit][Status][Discuss]
Description
Input
输入文件包含多组测试数据。
Output
T行,每行一个整数,表示你所求的答案。
Sample Input
7 4
5 6
Sample Output
121
HINT
1<=N, M<=50000
思路{
首先有D(N)=π(ki+1)------①其中ki为质因子pi的出现次数.一个质因子对答案的贡献就是ki+1
∑(i|n)∑(j|m)[gcd(i,j)=1]------②对于pi这个因子只能在i或j中出现,故合理的方案有(0,k1), (0,k1-1)...(0,0),(2,0),(3,0),,,(k2,0)有k1+k2+1对和①算出的贡献相等.即①等价于②
所以Ans= (n)∑(i=1) (m)∑(j=1) ∑(k|i) ∑(l|j) [gcd(k,l)=1]
那么直接把强上莫比乌斯反演:
Ans=(n)∑(i=1) (m)∑(j=1) (min(n,m))∑(d=1) (μ(d)* ∑(k|i) ∑(l|j) [gcd(k,l)|d])
考虑把莫比乌斯函数和后面的一大坨提到前面.
Ans=(min(n,m)) ∑(d=1) (μ(d) (n)∑(k=1) (m)∑(l=1) ( [gcd(k,l)|d]*( (n/d)*(m/d) ) )
再去掉gcd,
Ans=(min(n,m)) ∑(d=1) (μ(d) (n/d)∑(k=1) (m/d)∑(l=1) ( (n/ (d*k) ) *( (m / (d*l) ) ) )
里面可以变成
Ans=(min(n,m)) ∑(d=1) μ(d) [ (n/d)∑(k=1) (n/ (d*k) ) ] [ (m/d)∑(l=1) *(m / (d*l) ) ]
设F(x)=(x)∑(i=1) (x/i)
那么Ans=(min(n,m)) ∑(d=1) μ(d) F(n/d) F(m/d)
预处理μ的前缀和和F函数,再数论分块就可以了.
}
#include<bits/stdc++.h> #define LL long long #define RG register #define il inline #define N 50010 #define LL long long using namespace std; LL mu[N],f[N],p[N],n,m;bool vis[N]; void pre(){ mu[1]=1; for(int i=2;i<N;++i){ if(!vis[i])p[++p[0]]=i,mu[i]=-1; for(int j=1;j<=p[0]&&p[j]*i<N;++j){ vis[i*p[j]]=true; if(i%p[j])mu[i*p[j]]=-mu[i]; else { mu[i*p[j]]=0; break; } } } for(int i=2;i<N;++i)mu[i]+=mu[i-1]; for(int i=1;i<N;++i){ for(int l=1,r;l<=i;l=r+1){ r=i/(i/l); f[i]+=(i/l)*(r-l+1); } } } int main(){ int T;scanf("%d",&T); pre(); while(T--){ scanf("%lld%lld",&n,&m); if(n>m)swap(n,m); LL ans(0); for(int l=1,r;l<=n;l=r+1){ r=min(n/(n/l),m/(m/l)); ans+=(mu[r]-mu[l-1])*(f[n/l]*f[m/l]); }printf("%lld\n",ans); }return 0; }