bzoj 1409 Password 矩阵快速幂+欧拉函数
2017-07-30 14:30
253 查看
可以发现,该数组的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;
}
所以要矩阵快速幂搞出第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;
}
相关文章推荐
- bzoj 1409 Password 矩阵快速幂+欧拉函数
- 欧拉函数+矩阵快速幂 Password
- BZOJ 1409 Password 矩阵乘法+线性筛
- bzoj 1409: Password 矩阵乘法+线性筛
- bzoj(矩阵快速幂)
- BZOJ1009 单模板自动机 矩阵快速幂优化DP
- hdu4549 M斐波那契数列 【矩阵快速幂+快速幂+欧拉函数降次】
- 【jzoj5215】【BZOJ4870】【Shoi2017】【GDOI2018模拟7.9】【组合数问题】【矩阵快速幂】
- BZOJ1409 : Password
- BZOJ 1297 1297: [SCOI2009]迷路 拆点,矩阵快速幂
- hdu5667 Sequence 【矩阵快速幂+欧拉函数降次】
- [数列通项 矩阵快速幂] BZOJ4002 [JLOI2015]有意义的字符串
- [省选前题目整理][BZOJ 1297]迷路(矩阵快速幂)
- [BZOJ1875][SDOI2009]HH去散步(矩阵快速幂)
- 17.7.3小结、【矩阵快速幂】2017武大校赛I题:A simple math problem即nyoj2333、 bzoj2326
- [BZOJ 2326][HNOI 2011]数学作业(矩阵快速幂)
- [BZOJ3240][Noi2013]矩阵游戏 && 快速幂
- bzoj2510 弱题 【期望dp+循环矩阵快速幂】
- BZOJ1297: [SCOI2009]迷路 矩阵快速幂
- 【BZOJ 1409】 Password 数论(扩展欧拉+矩阵快速幂+快速幂)