习题:DZY Loves Math IV(杜教筛)
作者:互联网
题目
思路
\[设s(n,m)=\sum_{i=1}^{n}\varphi(ni)\\ \]然后显然分类讨论一下
当\(\mu(n)\ne 0\)的时候,那么就意味着将\(n\)进行质因数分解之后,指数都为\(1\)
\[\begin{aligned}s(n,m)&=\sum_{i=1}^{m}\varphi(ni)\\&=\sum_{i=1}^{m}\varphi(\frac{n}{gcd(n,i)})\varphi(igcd(n,i))\\&=\sum_{i=1}^{m}\varphi(\frac{n}{gcd(n,i)})\varphi(i)gcd(n,i)\\&=\sum_{i=1}^{m}\varphi(\frac{n}{gcd(n,i)})\varphi(i)\sum_{d|gcd(n,i)}\varphi(d)\\&=\sum_{i=1}^{m}\varphi(i)\sum_{d|gcd(n,i)}\varphi(\frac{nd}{gcd(n,i)})\\&=\sum_{i=1}^{m}\varphi(i)\sum_{d|gcd(n,i)}\varphi(\frac{n}{d})\\&=\sum_{d|n}\varphi(\frac{n}{d})\sum_{i=1}^{\lfloor\frac{m}{d}\rfloor}\varphi(id)\\&=\sum_{d|n}\varphi(\frac{n}{d})s(d,\lfloor\frac{m}{d}\rfloor)\end{aligned} \]当\(\mu(n)=0\)的时候
\[对于普通的\varphi(n)=n\prod\frac{p_k-1}{p_k}\\如果有一个数A满足\frac{n}{A}的质因数种类和n的质因数种类一样\\那么\varphi(nA)=An\prod\frac{p_k-1}{p_k}\\假设x是这样的一个数\\\begin{aligned}\sum_{i=1}^{m}\varphi(in)&=\sum_{i=1}^{m}\varphi(ix\frac{n}{x})\\&=\sum_{i=1}^{m}x\varphi(i\frac{n}{x})\\&=x\sum_{i=1}^{m}\varphi(i\frac{n}{x})\\&=x*s(\frac{n}{x},m)\end{aligned} \]\[\begin{aligned}ans&=\sum_{i=1}^{n}S(i,m)\end{aligned} \]之后就是\(S(n,m)\)的边界情况,
显然\(m=0\)是边界情况,那么\(S(n,m)=0\)
还有一个情况是\(n=1\),此时就是\(\sum_{i=1}^{m}\varphi(i)\),直接杜教筛处理即可
那么总共的时间复杂度就集中在了计算\(S(n,m)\)这个函数上面
然后观察这个暴力的形式,实际上跟杜教筛的形式是一样的,所以时间复杂度的计算也可以套过来
即时间复杂度为$O(m^{\frac{2}{3}}) $
代码
#include<unordered_map>
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const int mod=1e9+7;
int n,m;
int len;
int lenp,pri[100005],mu[1000005],phi[100005];
bool vis[100005];
long long mphi[100005];
long long ans=0;
unordered_map<int,long long> mp[100005];
unordered_map<int,long long> m1;
long long getphi(long long n)
{
if(n<=len)
return mphi[n];
if(m1.count(n))
return m1[n];
long long temp=1ll*n*(n+1)/2%mod;
for(long long l=2,r;l<=n;l=r+1)
{
r=min(1ll*n/(n/l),1ll*n);
temp=(temp-1ll*(r-l+1)*getphi(n/l)%mod)%mod;
}
temp=(temp%mod+mod)%mod;
return m1[n]=temp;
}
void sieve(int n)
{
len=n;
mu[1]=1;
phi[1]=mphi[1]=1;
for(int i=2;i<=n;i++)
{
if(vis[i]==0)
{
pri[++lenp]=i;
phi[i]=i-1;
mu[i]=-1;
}
for(int j=1;j<=lenp&&1ll*pri[j]*i<=n;j++)
{
vis[i*pri[j]]=1;
if(i%pri[j]==0)
{
mu[i*pri[j]]=0;
phi[i*pri[j]]=pri[j]*phi[i];
break;
}
mu[i*pri[j]]=mu[i]*mu[pri[j]];
phi[i*pri[j]]=phi[i]*phi[pri[j]]%mod;
}
mphi[i]=(mphi[i-1]+phi[i])%mod;
}
}
long long gets(int n,int m)
{
if(n==1)
return getphi(m);
if(m==1)
return phi[n];
if(mp[n].count(m))
return mp[n][m];
long long temp=0;
if(mu[n]!=0)
{
for(int d=1;d<=min(m,(int)sqrt(n));d++)
{
if(n%d==0)
{
if(d*d!=n)
temp=(temp+phi[d]*gets(n/d,m/(n/d))%mod)%mod;
temp=(temp+phi[n/d]*gets(d,m/d)%mod)%mod;
}
}
}
else
{
int x=1;
int t=n;
for(int i=2;i<=sqrt(n);i++)
{
if(n%i==0)
{
int e=0;
while(n%i==0)
{
e++;
n/=i;
}
if(e>1)
x*=i;
}
}
n=t;
temp=1ll*x*gets(n/x,m)%mod;
}
return mp[n][m]=temp;
}
int main()
{
cin>>n>>m;
sieve(100000);
for(int i=1;i<=n;i++)
{
ans=(ans+gets(i,m))%mod;
//cout<<gets(i,m)<<'\n';
}
cout<<ans;
return 0;
}
标签:frac,gcd,int,sum,varphi,杜教,long,Loves,习题 来源: https://www.cnblogs.com/loney-s/p/14354395.html