Codevs 加密算法

题目描述 Description
Rivest是密码学专家。近日他正在研究一种数列E={E[1],E[2],……,E[n]},
且E[1]=E[2]=p(p为一个质数),E[i]=E[i-2]*E[i-1]
例如{2,2,4,8,32,256,8192,……}就是p=2的数列。在此基础上他又设计了一种加密
算法,该算法可以通过一个密钥q将一个正整数n加密成另外一个正整数d,计
算公式为:d=E[n] mod q。现在Rivest想对一组数据进行加密,但他对程序设计不太
感兴趣,请你帮助他设计一个数据加密程序。

输入描述 Input Description
读入m,p。其中m表示数据个数,p用来生成数列E。
以下有m行,每行有2个整数n,q。n为待加密数据,q为密钥。
m,p,n,q都在int内
输出描述 Output Description
将加密后的数据按顺序输出到文件a.out。
第i行输出第i个加密后的数据。

样例输入 Sample Input
2 7
4 5
4 6

样例输出 Sample Output
3
1

这道题恶心得不得了。。说做法也简单,就是bzoj3884: 上帝与集合的正确用法 加上斐波那契矩阵就解决了。但是实现起来不是一般的恶心。。利用斐波那契矩阵+降幂大法我们可以解决p^fib[i]的问题,那么剩下的我们只需要计算一个快速幂就得到了答案。(直接降幂大法递归(推)处理其实不用写矩阵<-比如我)不知道降幂大法的可以自行百度上帝与集合的正确用法,这里就不多做解释。。。。。(毕竟我懒)
安利一发博客

#include
#include
#include
#include
using namespace std;
#define MAXN 100000
typedef long long LL;
LL m,q,n,mod;
typedef LL mat[2][2];
mat a,b,c;

LL pow_mod(LL x,LL y,LL mod)
{
    LL ret=1;
    while (y)
    {
        if (y&1)ret=ret*x%mod;
        x=x*x%mod;
        y>>=1;
    }
    return ret;
}

int prime[MAXN],topp=-1;
bool pflag[MAXN];

void init()
{
    for (int i=2;iif (!pflag[i])
        prime[++topp]=i;
        for (int j=0;j<=topp && i*prime[j]true;
            if (i%prime[j]==0)break;
        }
    }
}
LL get_phi(LL x)
{
    LL ret=1;
    for (int i=0;i<=topp && (LL)prime[i]*prime[i]<=x;i++)
    {
        if (x%prime[i]==0)
        {
            x/=prime[i];
            ret*=prime[i]-1;
            while (x%prime[i]==0)
            {
                x/=prime[i];
                ret*=prime[i];
            }
        }
    }
    if (x!=1)
    ret*=x-1;
    return ret;
}

int main()
{
    LL i,j,k,x,y,z;
    scanf("%lld %lld",&m,&q);
    LL phi_mod;
    init();
    while (m--)
    {
        scanf("%lld%lld",&n,&mod);
        if (mod==1)
        {
            printf("0\n");
            continue;
        }
        if (mod==q)
        {
            printf("0\n");
            continue;
        }
        phi_mod=get_phi(mod);
        a[0][0]=a[0][1]=a[1][0]=1;
        a[1][1]=0;
        b[0][0]=b[1][1]=1;
        b[1][0]=b[0][1]=0;
        n--;
        while (n)
        {
            if (n&1)
            {
                memset(c,0,sizeof(c));
                for (i=0;i<2;i++)
                for (j=0;j<2;j++)
                for (k=0;k<2;k++)
                c[i][j]=(c[i][j]+a[i][k]*b[k][j]%phi_mod)%phi_mod;
                memcpy(b,c,sizeof(b));
            }
            memset(c,0,sizeof(c));
            for (i=0;i<2;i++)
            for (j=0;j<2;j++)
            for (k=0;k<2;k++)
            c[i][j]=(c[i][j]+a[i][k]*a[k][j]%phi_mod)%phi_mod;
            memcpy(a,c,sizeof(c));
            n>>=1;
        }
        printf("%lld\n",pow_mod(q,b[0][0],mod));
}
}

你可能感兴趣的:(Codevs 加密算法)