password
Description
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 个加密后的数据。输入样例1 2 7 4 5 4
6 输入样例2 4 7 2 4 7 1 6 5 9 3
Sample Input
输入样例1
2 7
4 5
4 6
输入样例2
4 7
2 4
7 1
6 5
9 3
Sample Output
输出样例1
31
输出样例2
3011
solution
计算公式为:d=E[n] mod q
d=p^(fibonaqi[n]) mod q
所以 要 求斐波那契的第n项,但是我们发现long long也只能开到九十多项,想到了 降幂
这里就用到了 欧拉定理: a^b%k = a^(b%φ(k)) % k gcd(a,k)==1
a^b%k = a^(b%φ(k)+φ(k)) % k gcd(a,k)!=1
用这段神奇的code 来求 φ(k)
1 ll oula(ll t) 2 { 3 ll kk=t; 4 for(ll i=2;i*i<=t;++i) 5 if(t%i==0) 6 { 7 kk=kk-kk/i; 8 while(t%i==0) 9 t/=i; 10 } 11 if(t>1)kk=kk-kk/t; 12 return kk; 13 }
再用矩阵快速幂 求指数的斐波那契
最后快速幂即可 (注意要用long long)
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #define ll long long 5 #define mem(a,b) memset(a,b,sizeof(a)) 6 using namespace std; 7 8 int m,p,n; 9 ll q; 10 ll f[6][6],a[6][6],temp[6][6]; 11 ll mod; 12 13 ll oula(ll t) 14 { 15 ll kk=t; 16 for(ll i=2;i*i<=t;++i) 17 if(t%i==0) 18 { 19 kk=kk-kk/i; 20 while(t%i==0) 21 t/=i; 22 } 23 if(t>1)kk=kk-kk/t; 24 return kk; 25 } 26 27 inline void chu() 28 { 29 mem(f,0); 30 mem(a,0); 31 f[1][1]=1;f[2][2]=1; 32 a[1][1]=1;a[1][2]=1;a[2][1]=1; 33 } 34 35 inline ll cheng() 36 { 37 --n; 38 while(n) 39 { 40 if(n&1) 41 { 42 for(int i=1;i<=2;++i) 43 for(int j=1;j<=2;++j) 44 { 45 temp[i][j]=0; 46 for(int k=1;k<=2;++k) 47 temp[i][j]=(temp[i][j]+f[i][k]*a[k][j]%mod)%mod; 48 } 49 for(int i=1;i<=2;++i) 50 for(int j=1;j<=2;++j) 51 f[i][j]=temp[i][j]; 52 } 53 for(int i=1;i<=2;++i) 54 for(int j=1;j<=2;++j) 55 { 56 temp[i][j]=0; 57 for(int k=1;k<=2;++k) 58 temp[i][j]=(temp[i][j]+a[i][k]*a[k][j]%mod)%mod; 59 } 60 for(int i=1;i<=2;++i) 61 for(int j=1;j<=2;++j) 62 a[i][j]=temp[i][j]; 63 64 n>>=1; 65 } 66 return f[1][1]; 67 } 68 69 ll mi(ll x,ll c,ll qw) 70 { 71 ll ans=1; 72 while(c) 73 { 74 if(c&1) 75 ans=(ans*x)%qw; 76 x=(x*x)%qw; 77 c>>=1; 78 } 79 return ans; 80 } 81 82 int main(){ 83 scanf("%d%d",&m,&p); 84 for(int i=1;i<=m;++i) 85 { 86 scanf("%d%lld",&n,&q); 87 chu(); 88 mod=oula(q); 89 ll temp=cheng(); 90 printf("%lld\n",mi(p,temp,q)%q); 91 92 } 93 return 0; 94 }