[SDOI2015][bzoj3994] 约数个数和 [莫比乌斯反演]
题面:
思路:
首先,我们需要证明一个结论:d(i*j)等于sigma(gcd(x,y)==1),其中x为i的约数,y为j的约数
对于nm的每一个质因子pi分别考虑,设n = pi^ai + n',m = pi^bi + m'
那么显然质因子pi对d(nm)的贡献为(ai+bi+1)
同理,考虑右边的式子,我们发现质数pi对右侧做的贡献仍然是(ai+bi+1),即如下的(x,y)
(pi^ai,1) (pi^(ai-1),1) ..... (1,1) .....(1,pi^(bi-1)) (1,pi^bi)
因此左右两式相同
因此原待求表达式化为如下形式:
由莫比乌斯函数第二情况得:上式可化为
其中g(i)表示前半个式子中的那段东西,相当于d(i)的前缀和
于是O(Tsqrt(min(n,m))轻松解决
顺便说一句,求约数个数也有线性的方法
记录c[i]表示i的最小的质因子的次数
每次更新这个,然后同时用c[i]+1更新d[i*pri[j]]即可
Code:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define ll long long 6 using namespace std; 7 inline ll read(){ 8 ll re=0,flag=1;char ch=getchar(); 9 while(ch>'9'||ch<'0'){ 10 if(ch=='-') flag=-1; 11 ch=getchar(); 12 } 13 while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar(); 14 return re*flag; 15 } 16 ll mu[100010],pri[100010],c[100010],d[100010],cnt;bool vis[100010]; 17 void init(ll n){ 18 mu[1]=d[1]=c[1]=1;ll i,j,k; 19 for(i=2;i<=n;i++){ 20 if(!vis[i]){ 21 pri[++cnt]=i;mu[i]=-1;c[i]=1;d[i]=2; 22 } 23 for(j=1;(j<=cnt)&&(i*pri[j]<=n);j++){ 24 k=i*pri[j];vis[k]=1; 25 if(i%pri[j]==0){ 26 d[k]=d[i]/(c[i]+1)*(c[i]+2); 27 c[k]=c[i]+1;break; 28 } 29 mu[k]=-mu[i]; 30 d[k]=d[i]*d[pri[j]];c[k]=1; 31 } 32 } 33 for(i=1;i<=n;i++) mu[i]+=mu[i-1]; 34 for(i=1;i<=n;i++) d[i]+=d[i-1]; 35 } 36 ll n,m; 37 int main(){ 38 ll i,j,T=read(),ans;init(50000); 39 while(T--){ 40 n=read();m=read();ans=0; 41 if(n>m) swap(m,n); 42 for(i=1;i<=n;i=j+1){ 43 j=min(n/(n/i),m/(m/i)); 44 ans+=(mu[j]-mu[i-1])*d[n/i]*d[m/i]; 45 } 46 printf("%lld\n",ans); 47 } 48 }