P4213
xujindong_ · · 题解
杜教筛(给定积性函数
我们考虑人为地让取值变稀疏。有结论:对于任意
若
对
线性筛
剩下的问题是
#include<bits/stdc++.h>
using namespace std;
int t,bn,bn1,bn2,num,prime[46345],cnt,pi[1664515],mu[1664515];
long long n,r[92686],g[92686],f[92686];
bool vis[46345];
int mu_init(int n,int prime[],int mu[],bool vis[],int cnt=0){
mu[1]=1;
for(int i=2;i<=n;i++)vis[i]=1;
for(int i=2;i<=n;i++){
if(vis[i])prime[++cnt]=i,mu[i]=-1;
for(int j=1,v,p;i*prime[j]<=n;j++){
p=prime[j],v=i*p,vis[v]=0;
if(i%p==0){
mu[v]=0;
break;
}
else mu[v]=-mu[i];
}
}
return cnt;
}
int id(long long x){
return x<=bn?x:num-n/x+1;
}
void dfs(int dep,int now,int v){
if(now>bn||!vis[now])f[id(now)]+=v+1;
while(dep<=cnt&&prime[dep]<=min(bn1/now,bn)){
int p=prime[dep],nxt=now;
for(int i=1;1ll*nxt*p<=bn1;i++,nxt*=p)dfs(dep+1,nxt*p,i==1?-v:0);
dep++;
}
}
int main(){
cnt=mu_init(46340,prime,mu,vis);
for(int i=1;i<=46340;i++)pi[i]=pi[i-1]+vis[i];
cin>>t;
while(t--){
cin>>n,bn=sqrt(n),bn1=pow(n,2.0/3),bn2=pow(n,1.0/6);
for(long long l=1;l<=n;l=r[num]+1)r[++num]=n/(n/l),g[num]=r[num]-1;
for(int j=1;j<=cnt&&prime[j]<=bn2;j++){
int p=prime[j];
long long t=p*p;
for(int i=num;r[i]>=t;i--)g[i]-=g[id(r[i]/p)]-g[p-1];
}
for(int i=1;i<=num;i++)g[i]-=pi[min(r[i],(long long)bn2)]-1;
for(int i=1;i<=num;i++)f[i]=0;
dfs(pi[bn2]+1,1,1);
for(int i=1;i<=num&&r[i]<=bn1;i++)f[i]+=f[i-1];
for(int i=1;i<=num&&r[i]<=bn1;i++)f[i]-=g[i];
vector<int>rough;
for(int i=1;i<=bn;i++)if(g[i]!=g[i-1])rough.push_back(i);
for(int i=1;i<=num;i++){
if(r[i]<=bn1)continue;
int bn=sqrt(r[i]);
f[i]=f[bn]*g[bn]+1;
for(int j=0;j<rough.size()&&rough[j]<=bn;j++)f[i]-=mu[rough[j]]*g[id(r[i]/rough[j])];
for(int j=1;j<rough.size()&&rough[j]<=bn;j++)f[i]-=f[id(r[i]/rough[j])];
}
for(int i=1;i<=num;i++)f[i]-=pi[min(r[i],(long long)bn2)]+1;
for(int j=pi[bn2];j>=1;j--){
int p=prime[j];
long long t=1ll*p*p;
for(int i=num;r[i]>=t;i--)f[i]-=f[id(r[i]/p)]+j;
}
for(int i=1;i<=num;i++)f[i]++;
long long phi=0;
for(int i=1;i<=num;i++)phi+=(f[i]-f[i-1])*(n/r[i])*(n/r[i]+1)/2;
cout<<phi<<' '<<f[num]<<'\n',num=0;
}
return 0;
}
关于 PN 筛求块筛:
定义 Powerful Number(PN)为所有质因数的次数都大于一的数。可以证明 PN 的个数是
假如要求
存在一个函数
PN 可以通过搜索求出。现在只需要求
已知
我们要对每个整除位置求
剩下的整除位置可表示为
若
void powerful_number(long long n,int sg[],int sf[]){
vector<pair<long long,int> >pn;
for(int i=1;i<=cnt;i++){
int p=prime[i],gp[40];
long long pk=p;
hp[i][0]=1;
for(int j=1;pk<=n;j++,pk*=p){
gp[j]=calcg(pk,p),hp[i][j]=calcf(p,j);
for(int k=1;k<=j;k++)hp[i][j]=(hp[i][j]-1ll*gp[k]*hp[i][j-k]%mod+mod)%mod;
}
}
dfs(1,1,1,n,pn),sort(pn.begin(),pn.end());
for(int i=1,j=0,now=0;i<=num;i++){
while(j<pn.size()&&pn[j].first<=r[i])now=(now+pn[j++].second)%mod;
sh[i]=now;
}
for(int i=1;i<=bn;i++){
for(int j=1;i*j<=bn;j++){
int l=id(max(n/i/(j+1),(long long)bn)),r=id(n/i/j);
if(sh[i]!=sh[i-1]){
sf[i*j]=(sf[i*j]+1ll*(sh[i]-sh[i-1]+mod)*(sg[j]-sg[j-1]+mod))%mod;
sf[num-j+1]=(sf[num-j+1]+1ll*(sh[i]-sh[i-1]+mod)*(sg[r]-sg[l]+mod))%mod;
}
sf[num-j+1]=(sf[num-j+1]+1ll*(sg[i]-sg[i-1]+mod)*(sh[r]-sh[l]+mod))%mod;
}
}
for(int i=0;i<pn.size()&&pn[i].first<=bn;i++){
long long x=pn[i].first,lim=sqrt(n/x);
for(int j=bn/x+1;j<=lim;j++)sf[id(x*j)]=(sf[id(x*j)]+1ll*pn[i].second*(sg[j]-sg[j-1]+mod))%mod;
for(int j=max((n+x*bn-1)/(x*bn)-1,1ll);j<=lim;j++){
sf[num-j+1]=(sf[num-j+1]+1ll*pn[i].second*(sg[min(n/x/j,(long long)bn)]-sg[id(max(n/x/(j+1),(long long)lim))]+mod))%mod;
}
}
for(int i=1;i<=num;i++)sf[i]=(sf[i]+sf[i-1])%mod;
}