[BZOJ 3944]Sum:杜教筛

xiaoxiao2021-02-28  11

点击这里查看原题

贴一个杜教筛教程http://blog.csdn.net/skywalkert/article/details/50500009

预处理n^(2/3)+记忆化

注意虽然n的范围是2^31-1,没有爆int,但是n+1爆了,所以要用ll

/* User:Small Language:C++ Problem No.:2301 */ #include<bits/stdc++.h> #define ll long long #define inf 999999999 using namespace std; const int M=5e6; int cnt,prime[M]; bool not_prime[M]; map<int,ll> _phi,_mu; ll phi[M],mu[M]; ll calphi(ll n){ if(n<M) return phi[n]; map<int,ll>::iterator it; if((it=_phi.find(n))!=_phi.end()) return it->second; ll res=(ll)n*(n+1)/2; for(ll i=2,r;i<=n;i=r+1){ r=n/(n/i); res-=(r-i+1)*calphi(n/i); } return _phi[n]=res; } ll calmu(ll n){ if(n<M) return mu[n]; map<int,ll>::iterator it; if((it=_mu.find(n))!=_mu.end()) return it->second; ll res=1; for(ll i=2,r;i<=n;i=r+1){ r=n/(n/i); res-=(r-i+1)*calmu(n/i); } return _mu[n]=res; } void solve(){ int n; scanf("%d",&n); printf("%lld %lld\n",calphi(n),calmu(n)); } int main(){ freopen("data.in","r",stdin);// phi[1]=mu[1]=1; for(int i=2;i<M;i++){ if(!not_prime[i]){ prime[++cnt]=i; mu[i]=-1; phi[i]=i-1; } for(int j=1;j<=cnt&&i*prime[j]<M;j++){ not_prime[i*prime[j]]=1; if(i%prime[j]==0){ phi[i*prime[j]]=phi[i]*prime[j]; mu[i*prime[j]]=0; break; } phi[i*prime[j]]=phi[i]*phi[prime[j]]; mu[i*prime[j]]=-mu[i]; } } for(int i=1;i<M;i++){ phi[i]+=phi[i-1]; mu[i]+=mu[i-1]; } int t; scanf("%d",&t); while(t--) solve(); return 0; }
转载请注明原文地址: https://www.6miu.com/read-1100166.html

最新回复(0)