操作时旋转,很简单。
关键在于计数要避免超时。
算sum(N^(gcd(i,N)))/N , 1<=i<=N
d=gcd(i,N),枚举i很慢,转换思维,枚举d,算出这个d对应有多少个i,d的可能取值就是所有 d | N
i=d*x,N=d*y, 要让x和y互质,1<=x<=y,x的个数即phi(y),
互质问题,整除问题最终归结为phi
事实证明long long 很慢,能不用尽量不用
对于直接枚举质因数的话,用long long 和太多取模运算,TLE必定
11776840 | guowentian | 2154 | Accepted | 300K | 329MS | C++ | 2169B | 2013-07-13 16:54:07 |
#include <iostream> #include <cstdio> using namespace std; #define MAXN 40050 #define ll long long int n,p,ans; int prime[MAXN+10];int cnt; bool isprime[MAXN+10]; ll pow_mod(ll a,ll b) { ll res=1; while(b) { if(b&1) res=(res*a)%p; b>>=1; a=(a*a)%p; } return res; } void init() { for(int i=2;i<=MAXN;++i) if(!isprime[i]) { prime[cnt++]=i; for(int j=i;j<=MAXN;j+=i) isprime[j]=true; } } int euler(ll n) { ll res=n; for(int i=0;prime[i]*prime[i]<=n;++i) if(n%prime[i]==0) { res=res/prime[i]*(prime[i]-1); while(n%prime[i]==0) n/=prime[i]; } if(n>1) res=res/n*(n-1); return res%p; } int d[500][2],d_cnt; void decomp(int n) { d_cnt=0; for(int i=0;prime[i]*prime[i]<=n;++i) if(n%prime[i]==0) { d[d_cnt][0]=prime[i]; d[d_cnt][1]=0; while(n%prime[i]==0) { n/=prime[i]; d[d_cnt][1]++; } d_cnt++; } if(n>1) { d[d_cnt][0]=n; d[d_cnt][1]=1; d_cnt++; } } void dfs(int cur,int now) { if(cur==d_cnt) { ans=(ans+euler(n/now)*pow_mod(n,now-1))%p; return; } dfs(cur+1,now); int nn=now; for(int i=1;i<=d[cur][1];++i) { nn*=d[cur][0]; dfs(cur+1,nn); } } int main () { init(); int ncase; scanf("%d",&ncase); while(ncase--) { scanf("%d%d",&n,&p); ans=0; decomp(n); dfs(0,1); /*for(int i=1;i*i<=n;++i) // 也可以直接枚举,不用分解质因数,比较慢,极可能TLE { if(i*i==n) { ans+=euler(i)*pow_mod(n,i-1)%p; ans%=p; break; } else if(n%i==0) { ans=(ans+euler(i)*pow_mod(n,n/i-1))%p; //ans%=p; ans=(ans+euler(n/i)*pow_mod(n,i-1))%p; } }*/ cout<<ans<<endl; //printf("%lld\n",ans); } return 0; }