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想对一组数据进行加密,但他对程序设计不太感兴趣,请你帮助他设计一个数据加密程序。

输入

第一行读入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:
  又是一道数学题,很智障的,我们会发现素数p的次幂其实是个斐波那契额数列。
   首先需要用矩阵快速幂单个求出每一次的n对应的斐波那契额数列中的数。
   这时需要用到欧拉定理:a^x=a^(x%phi(q))%q,a与q互素,其中因为题面中说q<p,所以满足a与q互素
   如果不这样降幂会炸掉,考试的时候亲自尝试过。。。。。。
   得到降幂后的x,再用一个快速幂就可以啦
 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<algorithm>
 5 using namespace std;
 6 #define int long long
 7 __attribute__((optimize("O3")))int read() {
 8     int s=0,f=1;
 9     char ch=getchar();
10     while(ch>'9'||ch<'0') {
11         if(ch=='-') {
12             f=-1;
13         }
14         ch=getchar();
15     }
16     while(ch>='0'&&ch<='9') {
17         s=(s<<1)+(s<<3)+(ch^48);
18         ch=getchar();
19     }
20     return s*f;
21 }
22 __attribute__((optimize("O3")))int get_phi(int t) {
23     int kk=t;
24     for(int i=2; i*i<=t; i++) {
25         if(t%i==0) {
26             kk-=kk/i;
27             while(t%i==0) {
28                 t/=i;
29             }
30         }
31     }
32     if(t>1) {
33         kk-=kk/t;
34     }
35     return kk;
36 }
37 __attribute__((optimize("O3")))void fast(long long a[][3],long long b[][3],int q) {
38     long long temp[3][3]= {0};
39     for(int i=1; i<=2; i++) {
40         for(int j=1; j<=2; j++) {
41             for(int k=1; k<=2; k++) {
42                 temp[i][j]=(temp[i][j]+a[i][k]*b[k][j])%q;
43             }
44         }
45     }
46     b[1][1]=temp[1][1]%q;
47     b[1][2]=temp[1][2]%q;
48     b[2][1]=temp[2][1]%q;
49     b[2][2]=temp[2][2]%q;
50 }
51 __attribute__((optimize("O3")))long long speed(int i,int q) {
52     long long sin[3][3],a[3][3];
53     sin[1][1]=1;
54     sin[2][1]=1;
55     sin[1][2]=1;
56     sin[2][2]=0;
57     a[1][1]=1;
58     a[1][2]=0;
59     a[2][1]=0;
60     a[2][2]=1;
61     for(; i; i>>=1,fast(sin,sin,q)) {
62         if(i&1) {
63             fast(sin,a,q);
64         }
65     }
66     return a[1][2];
67 }
68 int m,p,q,n;
69 __attribute__((optimize("O3")))long long mul(int a,long long t,int mod) {
70     long long ans=1;
71     for(; t; t>>=1,(a=a*a%mod)) {
72         if(t&1) {
73             (ans=a*ans%mod);
74         }
75     }
76     return ans;
77 }
78 __attribute__((optimize("O3")))signed main() {
79     m=read();
80     p=read();
81     for(int i=1; i<=m; i++) {
82         n=read();
83         q=read();
84         int ji=get_phi(q);
85         int x=speed(n,ji);
86         x=x%ji;
87         long long ans=mul(p,x,q)%q;
88         printf("%lld\n",ans);
89     }
90     return 0;
91 }

 

 

转载于:https://www.cnblogs.com/forevergoodboy/p/7260067.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值