Description
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 想对一组数据进行加密,但他对程序设计不太感兴趣,请你帮助他设计一个数据加密程序。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 46 输入样例2 4 7 2 4 7 1 6 5 9 3Sample Input输入样例12 74 54 6输入样例24 72 47 16 59 3Sample Output输出样例131输出样例23011solution
计算公式为:d=E[n] mod q
d=p^(fibonaqi[n]) mod q
所以 要 求斐波那契的第n项,但是我们发现long long也只能开到九十多项,想到了 降幂
这里就用到了 欧拉定理: a^b%k = a^(b%φ(k)) % k gcd(a,k)==1
a^b%k = a^(b%φ(k)+φ(k)) % k gcd(a,k)!=1
用这段神奇的code 来求 φ(k)


1 ll oula(ll t) 2 { 3 ll kk=t; 4 for(ll i=2;i*i<=t;++i) 5 if(t%i==0) 6 { 7 kk=kk-kk/i; 8 while(t%i==0) 9 t/=i;10 }11 if(t>1)kk=kk-kk/t;12 return kk;13 }
再用矩阵快速幂 求指数的斐波那契
最后快速幂即可 (注意要用long long)


1 #include2 #include 3 #include 4 #define ll long long 5 #define mem(a,b) memset(a,b,sizeof(a)) 6 using namespace std; 7 8 int m,p,n; 9 ll q;10 ll f[6][6],a[6][6],temp[6][6];11 ll mod;12 13 ll oula(ll t)14 {15 ll kk=t;16 for(ll i=2;i*i<=t;++i)17 if(t%i==0)18 {19 kk=kk-kk/i;20 while(t%i==0)21 t/=i;22 }23 if(t>1)kk=kk-kk/t;24 return kk;25 }26 27 inline void chu()28 {29 mem(f,0);30 mem(a,0);31 f[1][1]=1;f[2][2]=1;32 a[1][1]=1;a[1][2]=1;a[2][1]=1;33 }34 35 inline ll cheng()36 {37 --n;38 while(n)39 {40 if(n&1)41 {42 for(int i=1;i<=2;++i)43 for(int j=1;j<=2;++j)44 {45 temp[i][j]=0;46 for(int k=1;k<=2;++k)47 temp[i][j]=(temp[i][j]+f[i][k]*a[k][j]%mod)%mod;48 }49 for(int i=1;i<=2;++i)50 for(int j=1;j<=2;++j)51 f[i][j]=temp[i][j];52 }53 for(int i=1;i<=2;++i)54 for(int j=1;j<=2;++j)55 {56 temp[i][j]=0;57 for(int k=1;k<=2;++k)58 temp[i][j]=(temp[i][j]+a[i][k]*a[k][j]%mod)%mod;59 }60 for(int i=1;i<=2;++i)61 for(int j=1;j<=2;++j)62 a[i][j]=temp[i][j];63 64 n>>=1;65 }66 return f[1][1];67 }68 69 ll mi(ll x,ll c,ll qw)70 {71 ll ans=1;72 while(c)73 {74 if(c&1)75 ans=(ans*x)%qw;76 x=(x*x)%qw;77 c>>=1;78 }79 return ans;80 }81 82 int main(){83 scanf("%d%d",&m,&p);84 for(int i=1;i<=m;++i)85 {86 scanf("%d%lld",&n,&q);87 chu();88 mod=oula(q);89 ll temp=cheng();90 printf("%lld\n",mi(p,temp,q)%q);91 92 }93 return 0;94 }