• Password (欧拉函数降幂)


    Password

    时间限制: 1 Sec  内存限制: 64 MB

    题目描述

    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

     这道题在考场小就想到了矩阵快速幂找次数(菲波那切数列),然后直接快速幂,但是菲波那切数列增长的很快,特别容易炸long long ,结果还没有用f数组一路推过去,边推边模得的分多,

    其实我的想法差的就是怎么把这么好的幂次降下来,这就要用到欧拉函数,p^n %k=p^(n%Φk)%k(当k为素数),当k不是素数时

    p^n %k=p^(n%Φk+Φk)%k,这样就能有效的把幂次降下来,然后矩阵快速幂+快速幂就好了

     1 #include<cmath>
     2 #include<queue>
     3 #include<cstdio>
     4 #include<cstdlib>
     5 #include<cstring>
     6 #include<iostream>
     7 #include<algorithm>
     8 using namespace std;
     9 int m,n;
    10 long long mo,p;
    11 long long f[5],a[5][5];
    12 long long c[5];
    13 long long phi;
    14 long long OL(long long t){
    15     long long k=t;
    16     for(int i=2;i*i<=t;i++){
    17         if(t%i==0){
    18             k=k-k/i;
    19             while(t%i==0){
    20                 t/=i;
    21             }
    22         }
    23     }
    24     if(t>1){
    25         k=k-k/t;
    26     }
    27     return k;
    28 }
    29 void cheng1(){
    30     memset(c,0,sizeof(c));
    31     for(int i=1;i<=2;i++){
    32         for(int j=1;j<=2;j++){
    33             c[i]+=f[j]*a[j][i];
    34             c[i]%=phi;
    35         }
    36     }
    37     for(int i=1;i<=2;i++){
    38         f[i]=c[i];
    39     }
    40 }
    41 long long d[5][5];
    42 void cheng2(){
    43     memset(d,0,sizeof(d));
    44     for(int k=1;k<=2;k++){
    45         for(int i=1;i<=2;i++){
    46             for(int j=1;j<=2;j++){
    47                 d[i][j]+=a[i][k]*a[k][j];
    48                 d[i][j]%=phi;
    49             }
    50         }
    51     }
    52     for(int i=1;i<=2;i++){
    53         for(int j=1;j<=2;j++){
    54             a[i][j]=d[i][j];
    55         }
    56     }
    57 }
    58 int main(){
    59     //freopen("a07.in","r",stdin);
    60     //freopen("password.in","r",stdin);
    61     //freopen("password.out","w",stdout);
    62     scanf("%d%lld",&m,&p);
    63     for(int i=1;i<=m;i++){
    64         scanf("%d%lld",&n,&mo);
    65         f[1]=1; f[2]=1; a[1][1]=1; a[1][2]=1; a[2][1]=1; a[2][2]=0;
    66         if(n<=2){
    67             printf("%lld
    ",p%mo);
    68             continue;
    69         }
    70         phi=OL(mo);
    71         n-=2;
    72         while(n){
    73             if(n&1){
    74                 cheng1();
    75             }
    76             cheng2();
    77             n=(n>>1);
    78         }
    79         long long t=f[1];
    80         long long ans=1,ch=p;
    81         while(t){
    82             if(t&1){
    83                 ans*=ch;
    84                 ans%=mo;
    85             }
    86             ch*=ch;
    87             ch%=mo;
    88             t=(t>>1);
    89         }
    90         printf("%lld
    ",ans%mo);
    91     }
    92     return 0;
    93 }
     
  • 相关阅读:
    左偏树(DP)问题
    Dinic问题
    卡特兰数问题
    《DSP using MATLAB》Problem 2.19
    《DSP using MATLAB》Problem 2.18
    《DSP using MATLAB》Problem 2.17
    《DSP using MATLAB》Problem 2.16
    《DSP using MATLAB》Problem 2.15
    《DSP using MATLAB》Problem 2.14
    《DSP using MATLAB》Problem 2.10
  • 原文地址:https://www.cnblogs.com/FOXYY/p/7265780.html
Copyright © 2020-2023  润新知