DestinHistoire

 

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编辑  收藏  举报

导航