首页 > 代码库 > Password (欧拉函数降幂)

Password (欧拉函数降幂)

Password

时间限制: 1 Sec  内存限制: 64 MB
提交: 55  解决: 35
[提交][状态][讨论版]

题目描述

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 }

 

 

Password (欧拉函数降幂)