BZOJ1409 Password - 矩阵乘法 - 快速幂 - 欧拉定理

27 篇文章 0 订阅
15 篇文章 0 订阅

传送门

题解:由于pq互质所以要求f[n]mod phi(q)。然后f[n]用矩乘计算即可。然后快速幂即可。

及说此题卡常需要先预处理出一些质数。

#include<iostream>
#include<cstring>
#include<cstdio>
#define MAXV 5
#define MAXP 1000000
#define lint long long
#define debug(x) cerr<<x
#define sp <<" "
#define ln <<endl
using namespace std;
int mod;
struct matrix{
    int v[MAXV][MAXV],n,m;
    inline matrix set_size(int _n=0,int _m=0)
    {
        n=_n,m=_m;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                v[i][j]=0;
        return *this;
    }
    matrix(int _n=0,int _m=0)
    {
        set_size(_n,_m);
    }
    inline matrix operator=(const matrix &b)
    {
        n=b.n,m=b.m;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                v[i][j]=b.v[i][j];
        return *this;
    }
    inline matrix operator*(const matrix &b)
    {
        matrix &a=(*this),c(a.n,b.m);
        if(a.m^b.n) return c;
        for(int i=1;i<=a.n;i++)
            for(int k=1;k<=b.m;k++)
                for(int j=1;j<=a.m;j++)
                    c.v[i][k]=(c.v[i][k]+(lint)a.v[i][j]*b.v[j][k]%mod)%mod;
        return c;
    }
    inline friend matrix operator*=(matrix &a,const matrix &b)
    {
        return a=a*b;
    }
}A(2,2),B(2,1);
bool notp[MAXP];int pri[MAXP],pri_cnt;
inline int LinearShaker(int n)
{
    notp[1]=true;pri_cnt=0;
    for(int i=2;i<=n;i++)
    {
        if(!notp[i]) pri[++pri_cnt]=i;
        for(int j=1;j<=pri_cnt;j++)
        {
            if((lint)pri[j]*i>n) break;
            notp[pri[j]*i]=true;
            if(i%pri[j]==0) break;
        }
    }
    return pri_cnt;
}
inline int get_phi(int x)
{
    if(x==1) return 1;
    int ans=x;
    for(int j=1;(lint)pri[j]*pri[j]<=x;j++)
        if(x%pri[j]==0)
        {
            ans=(lint)ans*(pri[j]-1)/pri[j];
            while(x%pri[j]==0) x/=pri[j];
        }
    return (x>1)?((lint)ans*(x-1)/x):ans;
}
inline int fast_pow(int x,int k,int mod)
{
    if(k==0) return 1%mod;
    if(k==1) return x%mod;
    int ans=fast_pow(x,k>>1,mod);
    ans=(lint)ans*ans%mod;
    if(k&1) ans=(lint)ans*x%mod;
    return ans;
}
inline matrix matrix_pow(const matrix &a,int k)
{
    if(k==1) return a;
    matrix ans=matrix_pow(a,k/2);
    ans*=ans;if(k&1) ans*=a;
    return ans;
}
inline int get_fn(int n,int m)
{
    if(n==1) return 1%m;
    mod=m;A.v[1][1]=A.v[1][2]=A.v[2][1]=1%m;A.v[2][2]=0;
    B.v[1][1]=1%m;B.v[2][1]=0;
    B=matrix_pow(A,n-1)*B;
    return B.v[1][1];
}
int main()
{
    LinearShaker(MAXP);
    int m,p;scanf("%d%d",&m,&p);
    while(m--)
    {
        int n,q;scanf("%d%d",&n,&q);
        printf("%d\n",fast_pow(p%q,get_fn(n,get_phi(q)),q));
    }
    return 0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值