BZOJ-1409 Password(矩阵快速幂+欧拉降幂)
题目描述
\(f(i)=f(i-2)\times f(i-1),f(1)=f(2)=p\)(\(p\) 是一个质数),\(m\) 次询问,每次询问给出数字 \(n,q\),求 \(f(n)\mod q\)。
数据范围:\(0<p,n<2^{31},0<q<p,0<m\leq 5000\)。
分析
\(f(1)=p,f(2)=p,f(3)=p^2,f(4)=p^3\),归纳可知:\(f(n)=p^{F(n)}\)(\(F(n)\) 为斐波那契数列第 \(n\) 项,\(f(1)=1,f(2)=1,f(3)=2\))。
欧拉降幂:\(f(n)\mod q=p^{F(n)\mod q}=p^{F(n)\mod \varphi(q)}\mod q\)。
线性筛预处理质数,对于每次询问,求 \(\varphi(q)\),再用矩阵快速幂求 \(F(n)\mod q\) 即可。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int prime[N+10],vis[N+10],cnt;
void init()
{
for(int i=2;i<=N;i++)
{
if(!vis[i])
prime[++cnt]=i;
for(int j=1;i*prime[j]<=N&&j<=cnt;j++)
{
vis[i*prime[j]]=1;
if(i%prime[j]==0)
break;
}
}
}
long long phi(long long n)
{
long long ans=n;
for(long long i=1;prime[i]*prime[i]<=n;i++)
{
while(n%prime[i]==0)
{
ans=ans/prime[i]*(prime[i]-1);
while(n%prime[i]==0)
n=n/prime[i];
}
}
if(n!=1)
ans=ans/n*(n-1);
return ans;
}
struct matrix
{
long long mat[3][3];
matrix()
{
memset(mat,0,sizeof(mat));
}
};
matrix mul(matrix A,matrix B,long long mod)
{
matrix ans;
for(int i=1;i<=2;i++)
for(int j=1;j<=2;j++)
for(int k=1;k<=2;k++)
ans.mat[i][j]=(ans.mat[i][j]+A.mat[i][k]*B.mat[k][j])%mod;
return ans;
}
matrix matrix_pow(matrix a,long long b,long long mod)
{
matrix ans;
for(int i=1;i<=2;i++)
for(int j=1;j<=2;j++)
ans.mat[i][j]=(i==j);
while(b)
{
if(b&1)
ans=mul(ans,a,mod);
b>>=1;
a=mul(a,a,mod);
}
return ans;
}
long long quick_pow(long long a,long long b,long long mod)
{
long long ans=1;
while(b)
{
if(b&1)
ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans%mod;
}
int main()
{
init();
long long m,p;
cin>>m>>p;
while(m--)
{
long long n,q;
scanf("%lld %lld",&n,&q);
long long PHI=phi(q);
matrix A;
A.mat[1][1]=1;A.mat[1][2]=1;
A.mat[2][1]=1;A.mat[2][2]=0;
A=matrix_pow(A,n-1,PHI);
long long temp=A.mat[1][1];
printf("%lld\n",quick_pow(p,temp,q));
}
return 0;
}
posted on 2020-11-27 19:34 DestinHistoire 阅读(51) 评论(0) 编辑 收藏 举报