BZOJ1409 Password 题解
作者:互联网
\(\mathrm{Describe.}\)
一种新的密码被研发出来了。想使用密码,首先需要用种子 \(\rm p\) 生成加密序列。具体的:
\(\rm E_i= p\ \ \ \ i=1,2\)
\(\rm E_i=E_{i-1}\times E_{i-2}\ \ \ i>2\)
之后,每次给出两个数 \(\rm n,q\),输出加密后的数字 \(\rm d\)。具体的加密方法为:
\(\rm d=E_n\ \%\ q\)
其中,\(\rm 0<n,q<2^{31},0<q<p,0<m\leq 5000\)
\(\mathrm{Solution.}\)
首先观察发现加密序列的指数是斐波那契数列,即,生成的序列形如:
\(\rm p^1,p^1,p^2,p^3,p^5......\)
又因为 \(\rm n\) 是 \(2^{31}\) 的量级,所以可以使用矩阵快速幂加速求出斐波那契数列。但是即使是这样的话这个指数本身依然大的离谱,无法接受。继续观察最终加密方法的数学式子,可以发现这个式子可以使用欧拉降幂处理。其中欧拉降幂:
\(\rm a^b\ \%\ c=a^{b\%\phi(c)+\phi(c)}\ \%\ c\)
所以我们可以把在求斐波那契数列时的 \(\rm mod\) 设置为 \(\phi(c)\),这样求出来的 \(\rm p\) 的指数就合理可计算了。
之后写个快速幂就好了。
\(\mathrm{Code.}\)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+5;
int prime[N],cnt;
bool vis[N];
int m,p,q,n,MOD;
struct Matrix
{
int mat[2][2];
}fib,final;
Matrix operator*(const Matrix &x,const Matrix &y)
{
Matrix tmp;
for(int i=0;i<=1;i++)
for(int j=0;j<=1;j++)
tmp.mat[i][j]=0;
for(int i=0;i<=1;i++)
for(int j=0;j<=1;j++)
for(int k=0;k<=1;k++)
tmp.mat[i][j]+=x.mat[i][k]*y.mat[k][j]%MOD,
tmp.mat[i][j]%=MOD;
return tmp;
}
int qpow(int a,int n)
{
int ans=1;
while(n)
{
if(n&1) ans=ans*a%q;
a=a*a%q;
n>>=1;
}
return ans;
}
int read()
{
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9')
{
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9')
{
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
}
return x*f;
}
void Prime_Init()
{
for(int i=2;i<=N-5;i++)
{
if(!vis[i]) prime[++cnt]=i;
for(int j=1;i*prime[j]<=N && j<=cnt; j++)
{
vis[i*prime[j]]=true;
if(!(i%prime[j])) break;
}
}
}
int getphi(int n)
{
int ans=n;
for(int i=1;prime[i]*prime[i]<=n;i++)
{
while(!(n%prime[i]))
{
ans=ans/prime[i]*(prime[i]-1);
while(!(n%prime[i])) n/=prime[i];
}
}
if(n!=1) ans=ans/n*(n-1);
return ans;
}
signed main()
{
Prime_Init();
m=read(),p=read();
while(m--)
{
n=read(),q=read();
int phiq=getphi(q);
MOD=phiq;
fib.mat[0][0]=fib.mat[0][1]=fib.mat[1][0]=1;
fib.mat[1][1]=0;
final.mat[0][0]=final.mat[1][1]=1;
final.mat[1][0]=final.mat[0][1]=0;
while(n)
{
if(n&1) final=final*fib;
fib=fib*fib;
n>>=1;
}
int final_ans=qpow(p,final.mat[0][1]%MOD+MOD)%q;
printf("%d\n",final_ans);
}
return 0;
}
标签:加密,Matrix,int,题解,BZOJ1409,rm,Password,final,const 来源: https://www.cnblogs.com/juruo-wsy/p/16529127.html