Password
题目
Rivest是密码学专家。近日他正在研究一种数列E = {E[1],E[2],……,E[n]},且E[1] = E[2] = p(p为一个质数),E[i] = E[i-2]×E[i-1] (若2<i<=n)。例如{2,2,4,8,32,256,8192,……}就是p = 2的数列。在此基础上他又设计了一种加密算法,该算法可以通过一个密钥q (q < p)将一个正整数n加密成另外一个正整数d,计算公式为:d = E[n] mod q。现在Rivest想对一组数据进行加密,但他对程序设计不太感兴趣,请你帮助他设计一个数据加密程序。INPUT
第一行读入m,p。其中m表示数据个数,p用来生成数列E。 以下有m行,每行有2个整数n,q。n为待加密数据,q为密钥。 数据范围: 0 < p n< 2^31 0 < q < p 0 < m <= 5000。OUTPUT
将加密后的数据按顺序输出到文件 第i行输出第i个加密后的数据。SAMPLE
INPUT1
2 74 54 6OUTPUT1
31INPUT2
4 72 47 16 59 3OUTPUT2
3011
解题报告
考试时候本以为推了个正解,又强行推出了实现,结果= =
还不如打个暴力
正解:
首先写个公式:
其中,phi(p)为p的欧拉函数。
不要问我怎么证,我不会
然后,我们可以得出,要求的显然就是p^fib(i)%q,其中fib(i)为斐波那契数列的第i项。
显然,正经递推斐波那契是会T的。所以我们考虑优化,显然可以用矩阵快速幂解决问题。
那么,剩下的就很简单了。直接快速幂就可以解决了。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 using namespace std; 5 typedef long long L; 6 inline int read(){ 7 int sum(0); 8 char ch(getchar()); 9 for(;ch<'0'||ch>'9';ch=getchar()); 10 for(;ch>='0'&&ch<='9';sum=sum*10+(ch^48),ch=getchar()); 11 return sum; 12 } 13 L m,p,n,q; 14 L fib; 15 L unit[2][2],start[2][2]; 16 inline void multi(L a[][2],L b[][2],L mod){ 17 L tmp[2][2]={0}; 18 for(int i=0;i<2;i++) 19 for(int j=0;j<2;j++) 20 for(int k=0;k<2;k++) 21 tmp[i][j]=(tmp[i][j]+a[i][k]*b[k][j])%mod; 22 for(int i=0;i<2;i++) 23 for(int j=0;j<2;j++) 24 b[i][j]=tmp[i][j]; 25 } 26 inline int get_phi(L x){ 27 L ret(x); 28 for(int i=2;i*i<=x;i++) 29 if(x%i==0){ 30 ret=ret-ret/i; 31 while(x%i==0) 32 x/=i; 33 } 34 if(x>1) 35 ret=ret-ret/x; 36 return ret; 37 } 38 inline L fi(L p,L mod){ 39 /* if(p==0) 40 return 0; 41 if(p==1||p==2) 42 return 1;*/ 43 start[0][0]=start[1][0]=start[0][1]=1,start[1][1]=0; 44 unit[0][0]=unit[1][1]=1,unit[1][0]=unit[0][1]=0; 45 while(p){ 46 if(p&1) 47 multi(start,unit,mod); 48 multi(start,start,mod); 49 p>>=1; 50 } 51 return unit[0][1]; 52 } 53 L mod; 54 inline L qpow(L a,L p,L mod){ 55 L ret(1); 56 while(p){ 57 if(p&1) 58 ret*=a,ret%=mod; 59 a*=a,a%=mod; 60 p>>=1; 61 } 62 return ret; 63 } 64 int main(){ 65 // freopen("1.in","r",stdin); 66 // freopen("1.out","w",stdout); 67 m=read(),p=read(); 68 while(m--){ 69 n=read(),q=read(); 70 mod=get_phi(q); 71 fib=fi(n,mod); 72 fib%=mod; 73 printf("%lld ",qpow(p,fib,q)%q); 74 } 75 }