线筛各种函数 元函数 恒等函数 单位函数 莫比乌斯函数 欧拉函数 因子个数函数 因子和函数
#include<bits/stdc++.h> #define ll long long using namespace std; const int maxn=1e6+10; int e[maxn]; int I[maxn]; int ID[maxn]; int phi[maxn]; int mu[maxn]; void init_e() { e[1]=1; } void init_I() { int n=maxn-1; for(int i=1;i<=n;i++) I[i]=1;} void init_ID(){ int n=maxn-1; for(int i=1;i<=n;i++) ID[i]=i;} bool vis[maxn]; int prime[maxn/7]; int tot=0; void init_mu(){ int n=maxn-1; tot=0; mu[1]=1; for(int i=2;i<=n;i++){ if(vis[i]==0) { prime[++tot]=i; mu[i]=-1; } for(int j=1;j<=tot && i*prime[j]<=n;j++){ vis[i*prime[j]]=1; if(i%prime[j]==0){break;} mu[i*prime[j]]=-mu[i]; } } } void init_phi(){ int n=maxn-1; tot=0; phi[1]=1; for(int i=2;i<=n;i++){ if(vis[i]==0) { prime[++tot]=i; phi[i]=i-1; } for(int j=1;j<=tot && i*prime[j]<=n;j++){ vis[i*prime[j]]=1; if(i%prime[j]==0){ phi[i*prime[j]]=phi[i]*prime[j]; break; }phi[i*prime[j]]=phi[i]*(prime[j]-1); } } } int d[maxn]; ll dd[maxn]; int mm[maxn]; // 最小因子相关的信息 void init_d(){ int n=maxn-1; tot=0; d[1]=1; for(int i=2;i<=n;i++){ if(vis[i]==0) {prime[++tot]=i; d[i]=2; mm[i]=2; } for(int j=1;j<=tot && i*prime[j]<=n;j++){ vis[i*prime[j]]=1; if(i%prime[j]==0){ d[i*prime[j]]=d[i]/mm[i]*(mm[i]+1); mm[i*prime[j]]=mm[i]+1; break; } d[i*prime[j]]=d[i]*2; mm[i*prime[j]]=2; } } } // ((x+1)*x+1)*x+1; // 转换成多项式 类似hash void init_dd(){ int n=maxn-1; tot=0; dd[1]=1; for(int i=2;i<=n;i++){ if(vis[i]==0) { prime[++tot]=i; dd[i]=i+1; mm[i]=i+1; } for(int j=1;j<=tot && i*prime[j]<=n;j++){ vis[i*prime[j]]=1; if(i%prime[j]==0){ mm[i*prime[j]]=mm[i]*prime[j]+1; dd[i*prime[j]]=dd[i]/mm[i]*mm[i*prime[j]] ; break; } dd[i*prime[j]]=dd[i]*dd[prime[j]]; mm[i*prime[j]]=1+prime[j]; } } } int main(){ init_e();init_I();init_ID(); init_mu();init_phi();init_d();init_dd(); }
对于莫比乌斯函数 和 欧拉函数 小于 1e8差不多都可线筛 1e12以内 杜教筛
代码针对洛古 p4213 n<=(1<<31)-1 杜教筛
#include<bits/stdc++.h> #define ll long long using namespace std; const int maxn=5e6+10; bool vis[maxn]; int prime[maxn/7]; int phi[maxn]; int mu[maxn]; int tot=0; ll sum_phi[maxn]; int sum_mu[maxn]; void get_mu_phi(){ int n=maxn-1; mu[1]=1; phi[1]=1; for(int i=2;i<=n;i++){ if(vis[i]==0) { prime[++tot]=i; phi[i]=i-1; mu[i]=-1; } for(int j=1;j<=tot && i*prime[j]<=n;j++){ vis[i*prime[j]]=1; if(i%prime[j]==0){ phi[i*prime[j]]=phi[i]*prime[j]; break; } mu[i*prime[j]]=-mu[i]; phi[i*prime[j]]=phi[i]*(prime[j]-1); } } for(int i=1;i<=n;i++) sum_mu[i]=sum_mu[i-1]+mu[i]; for(int i=1;i<=n;i++) sum_phi[i]=sum_phi[i-1]+phi[i]; } unordered_map<int,int> mp_mu; int get_mu(int n){ if(n<maxn) { return sum_mu[n]; } ll ans=0; for(int l=2,r;l<=n;l=r+1){ r=n/(n/l); int d=(n/l); if(d<maxn) { ans+=(r-l+1)*sum_mu[d]; } else { if(mp_mu.find(d)==mp_mu.end()) mp_mu[d]=get_mu(d); ans+=(r-l+1)*mp_mu[d]; } if(r==2147483647) break; } return mp_mu[n]=1-ans; } unordered_map<int,ll> mp_phi; ll get_phi(int n){ if(n<maxn) { return sum_phi[n]; } ll ans=0; for(int l=2,r;l<=n;l=r+1){ r=n/(n/l); int d=(n/l); if(d<maxn) { ans+=(r-l+1)*sum_phi[d]; } else { if(mp_phi.find(d)==mp_phi.end()) mp_phi[d]=get_phi(d); ans+=(r-l+1)*mp_phi[d]; } if(r==2147483647) break; } return mp_phi[n]=1ll*n*(n+1)/2-ans; } void work(int n){ ll x=get_phi(n); int y=get_mu(n); printf("%lld %d ",x,y); } int main(){ get_mu_phi(); int T; scanf("%d",&T); while(T--){ int n; scanf("%d",&n); work(n); } }
因子和函数前缀和 线筛 (求多个的时候效果突出),杜教都不咋地 整除分块才是王道
LightOJ - 1098 整除分块代码
#include<bits/stdc++.h> #define ll long long using namespace std; int main(){ int T; scanf("%d",&T); int tot=0; while(T--){ ll n; scanf("%lld",&n); ll ans=0; for(ll l=1,r;l<=n;l=r+1){ r=n/(n/l); ans+=1ll*(l+r)*(r-l+1)/2*(n/l); } //cout<<ans<<endl; //cout<<1ll*n*(n+1)/2<<endl; ans++; ans-=n; ans-=1ll*n*(n+1)/2; if(n==0) ans=0; printf("Case %d: %lld ",++tot,ans); } }
杜教推出来而是那个分块的........ 通过 I (恒等函数) id( 单位函数 ) = σ (因子和函数)
写个线筛的吧(自己写的 没过过题 随机暴力测了一些样例 过了)
#include<bits/stdc++.h> #define ll long long using namespace std; const int maxn=5e6+10; int vis[maxn]; int num[maxn]; int prime[maxn/7]; int sigma[maxn]; // yin zi he han shu int tot=0; int pow(int x,int n){ int ans=1; while(n){ if(n&1) ans=ans*x; x=x*x; n=n/2; } return ans; } void inint(){ int n=maxn-1; vis[1]=1; sigma[1]=1; for(int i=2;i<=n;i++){ // cout<<i<<endl; if(vis[i]==0) { prime[++tot]=i; vis[i]=i; num[i]=1; sigma[i]=i+1; } for(int j=1;j<=tot&&i*prime[j]<=n;j++){ vis[i*prime[j]]=prime[j]; if(i%prime[j]==0){ num[i*prime[j]]=num[i]+1;; sigma[i*prime[j]]=sigma[i]*(1-pow(vis[i],num[i]+1+1)) / (1-pow(vis[i],num[i]+1)); break; }else { num[i*prime[j]]=1; sigma[i*prime[j]]=sigma[i]*(1+prime[j]); } } } } int main(){ //cout<<pow(2,5)<<endl; inint(); //cout<<sigma[4]<<endl; int tot=0; while(1){ int n; cin>>n; cout<<sigma[n]<<endl; int ans=0; for(int i=1;i<=n;i++){ if(n%i==0) ans+=i; } cout<<ans<<endl; } }
hdu 5608 莫比乌斯反演+杜教筛
#include<bits/stdc++.h> #define ll long long using namespace std; const int maxn=5e6+10; const int mod=1e9+7; const int inv2=500000004; const int inv4=250000002; const int inv6=166666668; bool vis[maxn]; int prime[maxn/7]; int mu[maxn]; int tot=0; int sum_mu[maxn]; void get_mu_phi(){ int n=maxn-1; mu[1]=1; for(int i=2;i<=n;i++){ if(vis[i]==0) { prime[++tot]=i; mu[i]=-1; } for(int j=1;j<=tot && i*prime[j]<=n;j++){ vis[i*prime[j]]=1; if(i%prime[j]==0){ break; } mu[i*prime[j]]=-mu[i]; } } for(int i=1;i<=n;i++) sum_mu[i]=sum_mu[i-1]+mu[i]; } unordered_map<ll,ll> mp_mu; ll get_mu(ll n){ if(n<maxn) { return sum_mu[n]; } ll ans=0; for(int l=2,r;l<=n;l=r+1){ r=n/(n/l); int d=(n/l); if(d<maxn) { ans+=1ll*(r-l+1)*sum_mu[d]%mod; } else { if(mp_mu.find(d)==mp_mu.end()) mp_mu[d]=get_mu(d); ans+=1ll*(r-l+1)*mp_mu[d]%mod; } } return mp_mu[n]=(1-ans)%mod; } int add(int x){ int ans=1ll*x*(x+1)%mod*(2*x+1)%mod*inv6%mod; ans-=1ll*3*(x+1)%mod*x%mod*inv2%mod; ans=ans%mod; ans+=1ll*2*x%mod; ans=ans%mod; return ans; } int make(int l,int r){ return ( add(r)-add(l-1) )%mod; } void work(int n){ ll ans=0; for(int l=1,r;l<=n;l=r+1){ r=n/(n/l); int d=n/l; if(d<maxn){ ans+=1ll*make(l,r)*sum_mu[d]%mod; }else { if(mp_mu.find(d)==mp_mu.end()) mp_mu[d]=get_mu(d); ans+=1ll*make(l,r)*mp_mu[d]%mod; } } printf("%lld ",(ans%mod+mod)%mod); } int main(){ get_mu_phi(); int T; scanf("%d",&T); while(T--){ int n; scanf("%d",&n); work(n); } }
https://blog.csdn.net/v5zsq/article/details/52116285 大神的写法 (学不来)
https://www.cnblogs.com/acjiumeng/p/9739793.html 学不来的写法