1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > CCPC-Wannafly Winter Camp Day3 (Div2 onsite) F 小清新数论 欧拉函数的利用 莫比乌斯反演 杜教筛

CCPC-Wannafly Winter Camp Day3 (Div2 onsite) F 小清新数论 欧拉函数的利用 莫比乌斯反演 杜教筛

时间:2020-08-03 12:39:14

相关推荐

CCPC-Wannafly Winter Camp Day3 (Div2  onsite) F 小清新数论 欧拉函数的利用 莫比乌斯反演 杜教筛

F - 小清新数论

做法一:欧拉函数

#include<stdio.h>#include<bits/stdc++.h>using namespace std;#define LL long longconst int maxn = 1e7+9;const LL mod = 998244353;LL phi[maxn],miu[maxn],fac[maxn];//phi--欧拉函数表 miu--莫比乌斯函数表 fac--i最大的素因子辅助打phi表void init(){for (int i = 1; i < maxn; ++i) fac[i] = i;phi[1] = miu[1] = 1;for (int i = 2; i < maxn; ++i){if (fac[i] == i)for (int j = i << 1; j < maxn; j += i)fac[j] = i;if (i / fac[i] % fac[i]) phi[i] = (fac[i] - 1)*phi[i / fac[i]], miu[i] = -miu[i / fac[i]]; //如果b质数 a%b!=0 phi(a*b) = phi(a)*b - phi(a)else phi[i] = fac[i] * phi[i / fac[i]], miu[i] = 0;//当b是质数,a%b==0,phi(a*b)=phi(a)*b}for(int i=1;i<maxn;i++)phi[i]=phi[i]+phi[i-1];}int main(){init();LL n;cin>>n;LL NN=n;LL ans=0;for(LL i=1;i<=NN;i++){LL res=(phi[NN/i]*(LL)2-1)%mod;ans=(ans+miu[i]*res%mod)%mod;while(ans<0)ans+=mod;}printf("%lld\n",ans);}

做法二:莫比乌斯反演

#include<stdio.h>#include<bits/stdc++.h>using namespace std;typedef long long ll;const int mod=998244353;const int maxn=1e7+1;ll phi[maxn],miu[maxn],vis[maxn];void init(){for(int i=1;i<maxn;++i)vis[i]=i;phi[1]=miu[1]=1;for(int i=2;i<maxn;i++){if(vis[i]==i){for(int j=i<<1;j<maxn;j+=i)vis[j]=i;}if(i/vis[i]%vis[i])miu[i]= -miu[i/vis[i]];else miu[i]=0;}for(int i=1;i<maxn;i++)miu[i]=miu[i]+miu[i-1];}ll solve(int n,int m){ll ans=0;int N=min(n,m),r;for(int l =1;l<=N;l=r+1){r=min(n/(n/l),m/(m/l)); //取分块小的数ll res=(miu[r]-miu[l-1]+mod)%mod*(n/l)%mod*(n/l)%mod; //miu[r]-miu[l-1]表示l~r区间miu和,ans=(ans+res+mod)%mod;}return ans;}int main(){init();int n,r;scanf("%d",&n);ll ans=0,res;for(int l=1;l<=n;l=r+1){r=n/(n/l);res=(miu[r]-miu[l-1]+mod)%mod*solve(n/l,n/l)%mod;ans=(ans+res+mod)%mod;}printf("%lld\n",ans);return 0;}

做法三:杜教筛能过div1,跑了1423ms,对做法一中欧拉函数前n项和,欧拉函数前n项和进行杜教筛,然后套一个分块求解

#include<stdio.h>#include<bits/stdc++.h>#include<tr1/unordered_map>#define INV2 499122177using namespace std;typedef long long ll;const int N=1e7+20;const int mod=998244353;bool vis[N];int mu[N],sum1[N];long long phi[N],sum2[N];int cnt,prim[N];int e,e1;tr1::unordered_map<long long,long long>w,w1; //哈希 w用来求phi前缀和 w1用来求miu前缀和void get(int maxn){phi[1]=mu[1]=1;for(int i=2;i<=maxn;i++){if(!vis[i]){prim[++cnt]=i;mu[i]=-1;phi[i]=i-1;}for(int j=1;j<=cnt&&prim[j]*i<=maxn;j++){vis[i*prim[j]]=1;if(i%prim[j]==0){phi[i*prim[j]]=phi[i]*prim[j];break;}else mu[i*prim[j]]=-mu[i],phi[i*prim[j]]=phi[i]*(prim[j]-1);}}for(int i=1;i<=maxn;i++)sum1[i]=sum1[i-1]+mu[i],sum2[i]=(sum2[i-1]+phi[i])%mod; //打一个maxn的phi前缀和表 和miu前缀和表}int djsmu(long long x)//求miu前缀和{if(x<=10000000)return sum1[x];if(w[x])return w[x];int ans=1;for(long long l=2,r;l<=x;l=r+1){r=x/(x/l);ans-=(r-l+1ll)*djsmu(x/l);}return w[x]=ans;}long long djsphi(long long x)//求phi 前缀和{if(x<=10000000)return sum2[x];if(w1[x])return w1[x];long long ans=x%mod*(x+1)%mod*INV2%mod;for(long long l=2,r;l<=x;l=r+1){r=x/(x/l);ans=(ans-(r-l+1)%mod*djsphi(x/l)+mod)%mod;}while(ans<0)ans+=mod;return w1[x]=ans%mod;}int main(){get(10000000);ll n,r;scanf("%lld",&n);ll ans=0,res;for(ll l=1;l<=n;l=r+1){r=n/(n/l);res=(ll)(djsmu(r)-djsmu(l-1)+mod)%mod*((djsphi(n/l)%mod*(ll)2%mod-1+mod)%mod)%mod;ans=(ans+res+mod)%mod;}printf("%lld\n",ans);return 0;}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。