BZOJ 1409: Password 线性筛+矩阵乘法

来源:互联网 发布:windows更新有必要吗 编辑:程序博客网 时间:2024/06/09 15:24

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;}
0 0