题目链接
https://www.lydsy.com/JudgeOnline/problem.php?id=3884
分析
扩展欧拉定理裸题
欧拉定理及证明:
如果$(a,m)=1$,则$a^{\phi(m)} \equiv 1 \mod m$
$Prove:$设$x$取遍$m$的缩系,则$ax$取遍$m$的缩系,即
因为这样的$a$有$\phi(m)$个
由于$(x,m)=1$,保证$\prod x$ 存在模$m$意义下的逆元
所以
扩展欧拉定理:
如果
则
设$f(x)$为在模$x$意义下题目式子的值,那么
然后就可以记忆化搞一搞了
注意
求欧拉函数可以线性预处理也可以直接求,实践证明直接求不知道快到哪里去了
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
| #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <cctype> #define ll long long #define ri register int using std::sort; template <class T>inline void read(T &x){ x=0;int ne=0;char c; while(!isdigit(c=getchar()))ne=c=='-'; x=c-48; while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48; x=ne?-x:x;return ; } const int maxn=10000005; const int inf=0x7fffffff; int t,n; int mem[maxn]; int phi[maxn]; bool vis[maxn]; inline void get_table(){ bool is_pri[maxn]; int num[1000005],tot=0,tmp; memset(is_pri,0,sizeof(is_pri)); is_pri[1]=1; phi[1]=1; for(ri i=2;i<=maxn;i++){ //printf("%d\n",i); if(!is_pri[i]){ num[++tot]=i; phi[i]=i-1; } for(ri j=1;j<=tot;j++){ tmp=num[j]*i; if(tmp>=maxn)break; is_pri[tmp]=1; if(i%num[j]==0){ phi[tmp]=num[j]*phi[i]; break; } else { phi[tmp]=(num[j]-1)*phi[i]; } } } return ; } inline int get_phi(int x){ int res=x; for(ri i=2;i*i<=n;i++){ if(x%i==0){ res=res/i*(i-1); while(x%i==0)x=x/i; } } if(x>1)res=res/x*(x-1); return res; } int ksm(ll x,int c,int p){ ll ans=1,res=x; while(c){ if(c&1)ans=ans*res%p; res=res*res%p; c=c>>1; } return ans%p; } int f(int x){ if(x==1)return 0; if(vis[x])return mem[x]; int p=phi[x];//int p=get_phi(x); vis[x]=1; mem[x]=ksm(2,f(p)+p,x); return mem[x]; } int main(){ read(t); get_table(); while(t--){ read(n); printf("%d\n",f(n)); } return 0; }
|