您的位置:首页 > 其它

bzoj 1409 Password 矩阵快速幂+欧拉函数

2017-07-30 14:30 155 查看
可以发现,该数组的mi就是斐波那契数列

所以要矩阵快速幂搞出第n位

但是斐波那契数列上涨的很快,这就需要欧拉定理了

p^phi(q)%q=1(gcd(p,q)==1)

p是素数,所以可以用

然后需要5000个数的phi,q<=2^31

筛出sqrt(2^31)范围内的素数,然后直接找单个数的欧拉函数就好了

最后再套个快速幂就A了

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
int m,n,p,q,prime[80005],tot;
bool bo[80050];
long long a[3][3],b[3][3],c[3][3];
void getprime(int N=80005){
for(int i=2;i<=N;i++){
if(!bo[i])prime[++tot]=i;
for(int j=1;j<=tot&&i*prime[j]<=N;j++){
bo[i*prime[j]]=1;
if(!i%prime[j]) break;
}
}
}
void poww(long long A[3][3],long long B[3][3],long long C[3][3],int pp){
long long D[3][3]={0};
for(int j=1;j<=2;j++){
for(int i=1;i<=2;i++){
D[i][j]=0;
for(int k=1;k<=2;k++){
D[i][j]+=A[i][k]*B[k][j];
D[i][j]%=pp;
}
}
}
for(int j=1;j<=2;j++)
for(int i=1;i<=2;i++)
C[i][j]=D[i][j];
}
int getphi(int x){
int xx=x;
for(int i=1;prime[i]*prime[i]<=xx;i++){
if(!(xx%prime[i])){
x/=prime[i];x*=(prime[i]-1);
while(!(xx%prime[i]))xx/=prime[i];
}
}
if(xx!=1){x/=xx;x*=(xx-1);}
return x;
}
int main()
{
scanf("%d%d",&m,&p);
getprime();
for(int i=1;i<=m;i++){
//printf("i==%d\n",i);
scanf("%d%d",&n,&q);
a[1][1]=a[1][2]=a[2][1]=1; a[2][2]=0;
b[1][1]=b[1][2]=1;
c[1][1]=c[2][2]=1; c[1][2]=c[2][1]=0;
int qq=getphi(q);
//printf("q==%d  qq==%d\n",q,qq);
if(n<=2){
printf("%d\n",p%q);
continue;
}
n-=2;
while(n){
if(n&1) poww(c,a,c,qq);
poww(a,a,a,qq);
n>>=1;
}
poww(b,c,b,qq);
int mi=b[1][1];
//printf("mi==%d\n",mi);
long long pp=p,ans=1;
while(mi){
if(mi&1) ans=(ans*pp)%q;
pp=(pp*pp)%q;
mi>>=1;
}
printf("%lld\n",ans%q);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: