Password (欧拉函数降幂)
Password
时间限制: 1 Sec 内存限制: 64 MB题目描述
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想对一组数据进行加密,但他对程序设计不太感兴趣,请你帮助他设计一个数据加密程序。
输入
第一行读入m,p。其中m表示数据个数,p用来生成数列E。 以下有m行,每行有2个整数n,q。n为待加密数据,q为密钥。 数据范围: 0 < p n< 2^31 0 < q < p 0 < m <= 5000。
输出
将加密后的数据按顺序输出到文件 第i行输出第i个加密后的数据。 输入样例1 2 7 4 5 4 6 输入样例2 4 7 2 4 7 1 6 5 9 3
样例输入
输入样例1
2 7
4 5
4 6
输入样例2
4 7
2 4
7 1
6 5
9 3
样例输出
输出样例1
3
1
输出样例2
3
0
1
1
solution
这道题在考场小就想到了矩阵快速幂找次数(菲波那切数列),然后直接快速幂,但是菲波那切数列增长的很快,特别容易炸long long ,结果还没有用f数组一路推过去,边推边模得的分多,
其实我的想法差的就是怎么把这么好的幂次降下来,这就要用到欧拉函数,p^n %k=p^(n%Φk)%k(当k为素数),当k不是素数时
p^n %k=p^(n%Φk+Φk)%k,这样就能有效的把幂次降下来,然后矩阵快速幂+快速幂就好了
1 #include<cmath> 2 #include<queue> 3 #include<cstdio> 4 #include<cstdlib> 5 #include<cstring> 6 #include<iostream> 7 #include<algorithm> 8 using namespace std; 9 int m,n; 10 long long mo,p; 11 long long f[5],a[5][5]; 12 long long c[5]; 13 long long phi; 14 long long OL(long long t){ 15 long long k=t; 16 for(int i=2;i*i<=t;i++){ 17 if(t%i==0){ 18 k=k-k/i; 19 while(t%i==0){ 20 t/=i; 21 } 22 } 23 } 24 if(t>1){ 25 k=k-k/t; 26 } 27 return k; 28 } 29 void cheng1(){ 30 memset(c,0,sizeof(c)); 31 for(int i=1;i<=2;i++){ 32 for(int j=1;j<=2;j++){ 33 c[i]+=f[j]*a[j][i]; 34 c[i]%=phi; 35 } 36 } 37 for(int i=1;i<=2;i++){ 38 f[i]=c[i]; 39 } 40 } 41 long long d[5][5]; 42 void cheng2(){ 43 memset(d,0,sizeof(d)); 44 for(int k=1;k<=2;k++){ 45 for(int i=1;i<=2;i++){ 46 for(int j=1;j<=2;j++){ 47 d[i][j]+=a[i][k]*a[k][j]; 48 d[i][j]%=phi; 49 } 50 } 51 } 52 for(int i=1;i<=2;i++){ 53 for(int j=1;j<=2;j++){ 54 a[i][j]=d[i][j]; 55 } 56 } 57 } 58 int main(){ 59 //freopen("a07.in","r",stdin); 60 //freopen("password.in","r",stdin); 61 //freopen("password.out","w",stdout); 62 scanf("%d%lld",&m,&p); 63 for(int i=1;i<=m;i++){ 64 scanf("%d%lld",&n,&mo); 65 f[1]=1; f[2]=1; a[1][1]=1; a[1][2]=1; a[2][1]=1; a[2][2]=0; 66 if(n<=2){ 67 printf("%lld\n",p%mo); 68 continue; 69 } 70 phi=OL(mo); 71 n-=2; 72 while(n){ 73 if(n&1){ 74 cheng1(); 75 } 76 cheng2(); 77 n=(n>>1); 78 } 79 long long t=f[1]; 80 long long ans=1,ch=p; 81 while(t){ 82 if(t&1){ 83 ans*=ch; 84 ans%=mo; 85 } 86 ch*=ch; 87 ch%=mo; 88 t=(t>>1); 89 } 90 printf("%lld\n",ans%mo); 91 } 92 return 0; 93 }