Description
Rivest是密码学专家。近日他正在研究一种数列E = {E[1],E[2],……,E[n]},
且E[1] = E[2] = p(p为一个质数),E[i] = E[i-2]*E[i-1] (若小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
3
1
输出样例2
3
0
1
1
解法:
E[i]=p^f[i]
f[i]表示斐波那契数列的第i项
E[i]%q
=p^f[i]%q
因为q
///BZOJ 1409 线形筛
#include <bits/stdc++.h>
using namespace std;
///求解p^f(n)%q,其中f(n)为fib的第n项
typedef long long LL;
const int maxn = 100010;
LL phi;
struct mat{
LL a[2][2];
void init(){
memset(a, 0, sizeof(a));
}
};
mat operator * (mat a, mat b){
mat res;
res.init();
for(int i=0; i<2; i++)
for(int j=0; j<2; j++)
for(int k=0; k<2; k++)
res.a[i][j]=(res.a[i][j]+a.a[i][k]*b.a[k][j]%phi)%phi;
return res;
}
int powmod(int x, int y, int mod)
{
int ans=1LL;
while(y){
if(y&1) ans=(long long)ans*x%mod;
x=(long long)x*x%mod;
y>>=1;
}
return ans%mod;
}
int pri[maxn];
bool mark[maxn];
int tot, T, p, n, q;
void xianxingsai(){
memset(mark, 0, sizeof(mark));
for(int i=2; i<maxn; i++){
if(!mark[i]) pri[++tot]=i;
for(int j=1; j<=tot&&i*pri[j]<maxn; j++){
mark[i*pri[j]]=1;
if(i%pri[j]==0){
break;
}
}
}
}
int f1(int x)
{
int ans=x;
for(int i=1; i<=tot&&(long long)pri[i]*pri[i]<=x; i++)
if(x%pri[i]==0){
while(x%pri[i]==0) x/=pri[i];
ans=ans/pri[i]*(pri[i]-1);
}
if(x!=1) ans=ans/x*(x-1);
return ans;
}
int f2(int x){
x--;
mat a, b;
a.a[0][0]=a.a[0][1]=a.a[1][0]=1;
a.a[1][1]=0;
b.a[0][0]=1; b.a[1][0]=0;
while(x){
if(x&1) b=a*b;
a=a*a;
x>>=1;
}
return b.a[0][0];
}
int main()
{
scanf("%d%d", &T,&p);
xianxingsai();
while(T--){
scanf("%d%d", &n,&q);
phi=f1(q);
int ans = powmod(p,f2(n),q);
printf("%d\n", ans);
}
return 0;
}