Luogu P2158 儀仗隊【莫比烏斯反演】【線性篩】
阿新 • • 發佈:2021-11-08
前言
蒟蒻又來水部落格了!!!
昨天聽馮巨講解了莫比烏斯反演+線性篩法,馬上來寫一道模板題;
首先分析題意,我們用腦子推一下就知道了答案
中間是用尤拉函式,下面是用莫比烏斯反演。
兩種方法求答案,但是用莫比烏斯+分塊要快很多。
先放尤拉函式的程式碼:
點選檢視程式碼
#include<bits/stdc++.h> using namespace std; const int maxn=50000; int vis[maxn]; int prime[maxn]; int phi[maxn]; int sum[maxn]; void get_phi(){//線性求尤拉函式字首和 phi[1]=1; int cnt=0; for(int i=2;i<maxn;i++){ if(!vis[i]){ vis[i]=i; prime[cnt++]=i;//質數 phi[i]=i-1;//尤拉函式 } for(int j=0;j<cnt;j++){ if(i*prime[j]>maxn) break; vis[i*prime[j]]=prime[j]; if(i%prime[j]==0){//不是最小質因子 phi[i*prime[j]]=phi[i]*prime[j];//積性函式 break; } phi[i*prime[j]]=phi[i]*phi[prime[j]]; } } } int main() { get_phi(); sum[1]=1; for(int i=2;i<=maxn;i++){ sum[i]=sum[i-1]+phi[i]; } int n; cin>>n; if(n==1){//特判 cout<<0<<endl; } else{ cout<<2*sum[n-1]+1<<endl; } return 0; }
馬上就是,用莫比烏斯反演的程式碼:
點選檢視程式碼
#include<bits/stdc++.h> using namespace std; #define il inline #define re register #define debug printf("Now is Line : %d\n",__LINE__) #define file(a) freopen(#a".in","r",stdin);freopen(#a".out","w",stdout) #define mod 1000000007 il int read() { re int x=0,f=1;re char c=getchar(); while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();} while(c>='0'&&c<='9') x=x*10+c-48,c=getchar(); return x*f; } #define maxn 40000 int mu[maxn+5],prim[maxn+5],vis[maxn+5],cnt,n,ans; signed main() { n=read()-1; if(!n) return puts("0"),0; mu[1]=1; for(re int i=2;i<=n;++i) { if(!vis[i]) prim[++cnt]=i,mu[i]=-1; for(re int j=1;j<=cnt;++j) { if(prim[j]*i>n) break; vis[prim[j]*i]=1; if(i%prim[j]==0) break; mu[i*prim[j]]=-mu[i];//定義求μ } } for(re int i=1;i<=n;++i) mu[i]+=mu[i-1]; for(re int l=1,r;l<=n;l=r+1)//分塊 { r=n/(n/l); ans+=(mu[r]-mu[l-1])*(n/l)*(n/r); } printf("%d",ans+2);//正上方和正右方的兩點 return 0; }