题目描述 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));
}
}