bzoj 1409 Password
题目大意:
一种数列E = {E[1],E[2],……,E[n]}
且E[1] = E[2] = p(p为一个质数),E[i] = E[i-2]*E[i-1] (若2<i<=n)
在此基础上他又设计了一种加密算法,该算法可以通过一个密钥q (q < p)将一个正整数n加密成另外一个正整数d,计算公式为:d = E[n] mod q
思路:
首先可以想到快速幂
然后就是求一个数的斐波那契n项次方
因为斐波那契n项很大 所以log n很大会炸
因为p^phi(q)%q=1,注意q不一定是质数
所以只需要求出 f[i]%phi(q) 然后快速幂
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstdlib> 5 #include<cstring> 6 #include<algorithm> 7 #include<vector> 8 #include<queue> 9 #define inf 2139062143 10 #define ll long long 11 #define MAXN 100100 12 using namespace std; 13 inline ll read() 14 { 15 ll x=0,f=1;char ch=getchar(); 16 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 17 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 18 return x*f; 19 } 20 ll p[MAXN],ntp[MAXN],cnt,n,m,mod,T,m1; 21 struct mat {ll num[2][2];}; 22 mat mul(mat x,mat y) 23 { 24 mat res; 25 memset(res.num,0,sizeof(res.num)); 26 for(ll i=0;i<2;i++) 27 for(ll j=0;j<2;j++) 28 for(ll k=0;k<2;k++) 29 (res.num[i][j]+=x.num[i][k]*y.num[k][j])%=m1; 30 return res; 31 } 32 ll mat_q_pow(ll n) 33 { 34 if(n<=0) return 0; 35 mat t,res; 36 memset(res.num,0,sizeof(res.num)); 37 t.num[0][0]=t.num[0][1]=t.num[1][0]=1,t.num[1][1]=0; 38 res.num[0][0]=res.num[1][1]=1; 39 while(n) 40 { 41 if(n&1) res=mul(res,t); 42 t=mul(t,t); 43 n>>=1; 44 } 45 return res.num[0][1]; 46 } 47 void mem() 48 { 49 for(ll i=2;i<MAXN;i++) 50 { 51 if(!ntp[i]) p[++cnt]=i; 52 for(ll j=1;p[j]*i<MAXN;j++) 53 { 54 ntp[p[j]*i]=1; 55 if(i%p[j]==0) break; 56 } 57 } 58 } 59 void phi(ll x) 60 { 61 ll res=x; 62 for(ll i=1;p[i]*p[i]<=x;i++) 63 if(x%p[i]==0) 64 { 65 res/=p[i],res*=p[i]-1; 66 while(x%p[i]==0) x/=p[i]; 67 } 68 if(x!=1) res/=x,res*=x-1; 69 m1=res; 70 } 71 ll num_q_pow(ll k,ll x) 72 { 73 ll res=1; 74 while(x) 75 { 76 if(x&1) (res*=k)%=mod; 77 (k*=k)%=mod,x>>=1; 78 } 79 return res; 80 } 81 int main() 82 { 83 T=read(),n=read(); 84 mem(); 85 while(T--) 86 { 87 m=read(),mod=read(); 88 phi(mod); 89 printf("%lld\n",num_q_pow(n,mat_q_pow(m))%mod); 90 } 91 }