2019 西安邀请赛B. Product 杜教筛

    xiaoxiao2025-04-24  14

    B. Product

    我们先求幂ans:

                          

    切换枚举次序:

                         

    将互质转化为欧拉函数:

                                              

    对于比较大的前缀和欧拉函数Sn,我们使用杜教筛:

                                                     

                                             

    对于较大的前缀和 xd(x) :

                                   

    那么,这题就做完咯。

    #include<bits/stdc++.h> #define ll long long using namespace std; const int maxn=5e6+5,N=5e6; int vis[maxn],phi[maxn],pri[maxn/10],d[maxn],cnt,mod; unordered_map<int,int>mp,mp2; void add(int &x,int y) { if(y<0) x+=y; else x=x-mod+y; if(x<0) x+=mod; } void init(int n) { phi[1]=d[1]=1; for(int i=2;i<=n;i++) { if(!vis[i]) pri[++cnt]=i,d[i]=2,phi[i]=i-1; for(int j=1;j<=cnt&&pri[j]*i<=n;j++) { vis[pri[j]*i]=1; if(i%pri[j]) phi[i*pri[j]]=phi[i]*phi[pri[j]],d[i*pri[j]]=d[i]*2; else { phi[i*pri[j]]=phi[i]*pri[j]; int sum=1,x=i; while(x%pri[j]==0) x/=pri[j],sum++; d[i*pri[j]]=d[i]/sum*(sum+1); break; } } } for(int i=1;i<=n;i++) { add(phi[i],phi[i-1]); d[i]=1ll*d[i]*i%mod; add(d[i],d[i-1]); } } int ksm(ll x,int y,int M) { ll res=1; while(y) { if(y&1) res=res*x%M; x=x*x%M; y/=2; } return res; } int Abs(int x) { if(x<0) x+=mod; return x; } int calc(int l,int r) { return 1ll*(l+r)*(r-l+1)/2%mod; } int work(int n) { if(n<=N) return d[n]; if(mp2[n]) return mp2[n]; int ans=0; for(int l=1,r;l<=n;l=r+1) { r=n/(n/l); add(ans,1ll*calc(l,r)*calc(1,n/l)%mod); } return mp2[n]=ans; } int dfs(int n) { if(n<=N) return phi[n]; if(mp[n]) return mp[n]; int ans=calc(1,n),res=0; for(int l=2,r;l<=n;l=r+1) { r=n/(n/l); add(res,1ll*(r-l+1)*dfs(n/l)%mod); } add(ans,-res); return mp[n]=ans; } int main() { int n,m,p,ans=0; cin>>n>>m>>p; mod=p-1; init(N); for(int l=1,r;l<=n;l=r+1) { r=n/(n/l); add(ans,1ll*(2ll*dfs(n/l)-1)%mod*Abs(work(r)-work(l-1))%mod); } cout<<ksm(m,ans,p); }

     

    最新回复(0)