BZOJ 1409 快速冪+歐拉定理

Description

Rivest是密碼學專家。近日他正在研究一種數列E = {E[1],E[2],……,E[n]},
且E[1] = E[2] = p(p爲一個質數),E[i] = E[i-2]*E[i-1] (若2<i<=n)。
例如{2,2,4,8,32,256,8192,……}就是p = 2的數列。在此基礎上他又設計了一種加密算法,該算法可以通過一個密鑰q (q < p)將一個正整數n加密成另外一個正整數d,計算公式爲:d = E[n] mod q。現在Rivest想對一組數據進行加密,但他對程序設計不太感興趣,請你幫助他設計一個數據加密程序。

Input

第一行讀入m,p。其中m表示數據個數,p用來生成數列E。 以下有m行,每行有2個整數n,q。n爲待加密數據,q爲密鑰。 數據範圍: 0 < p n< 2^31 0 < q < p 0 < m <= 5000。

Output

將加密後的數據按順序輸出到文件 第i行輸出第i個加密後的數據。 輸入樣例1 2 7 4 5 4 6 輸入樣例2 4 7 2 4 7 1 6 5 9 3

Sample Input

輸入樣例1
2 7
4 5
4 6
輸入樣例2
4 7
2 4
7 1
6 5
9 3

Sample Output

輸出樣例1
3
1

輸出樣例2
3
0
1
1
作爲一個良心的人,我會粘題面的哈哈,因爲防止BZOJ 炸掉沒有辦法看題面。。

又是考試題,比較水,手推一下E[n]的係數是斐波那契數列,但是沒辦法mod,然後因爲p,q互素,那麼用歐拉定理就好了,用矩陣乘優化,模數爲phi(q),然後再普通快速冪就好了,此題爆int。

#include <stdio.h>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;
const int MAXN = 60000;
ll m,p,q,n,Mod,cnt;
int prime[MAXN+5];
bool _prime[MAXN+5];
 
 
template<typename _t>
inline _t read(){
    _t x=0,f=1;
    char ch=getchar();
    for(;ch>'9'||ch<'0';ch=getchar())if(ch=='-')f=-f;
    for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+(ch^48);
    return x*f;
}
 
void get_prime(){
    for(int i=2;i<=MAXN;i++){
        if(!_prime[i])prime[++cnt]=i;
        for(int j=1;j<=cnt&&i*prime[j]<=MAXN;j++){
            _prime[i*prime[j]]=1;
            if(i%prime[j]==0)break;
        }
    }
}
 
inline ll fast(ll p,ll n,ll q){
    ll ans = 1;
    for(;n;n>>=1,p=p*p%q)
        if(n&1)
            ans=ans*p%q;
    return ans;
}
 
ll get_phi(ll x){
    if(x==1)return 1;
    ll ans=1;
    for(int i=1;prime[i]*prime[i]<=x;i++){
        if(x%prime[i]==0){
            ans *= prime[i]-1;
            x/=prime[i];
        }
        while(x%prime[i]==0){
            ans*=prime[i];
            x/=prime[i];
        }
    }
    if(x!=1)ans*=x-1;
    return ans;
}
 
struct matrix{
    ll a[5][5];
    matrix(){
        memset(a,0,sizeof a);
    }
};
 
inline matrix operator * (matrix a,matrix b){
    matrix ans;
    for(int i=1;i<=2;i++)
        for(int j=1;j<=2;j++)
            for(int k=1;k<=2;k++)
                ans.a[i][j]=(ans.a[i][j]+a.a[i][k]*b.a[k][j]%Mod)%Mod;
    return ans;
}
 
inline matrix operator ^ (matrix a,ll k){
    matrix ans;
    for(int i=1;i<=2;i++)ans.a[i][i]=1;
    for(;k;k>>=1,a=a*a)
        if(k&1)
            ans=ans*a;
    return ans;
}
 
int main(){
    get_prime();
    m=read<ll>();
    p=read<ll>();
    while(m--){
        n=read<ll>();
        q=read<ll>();
        Mod = get_phi(q);
        matrix tmp;
        tmp.a[1][1]=tmp.a[1][2]=tmp.a[2][1]=1;
        if(n>1)
            tmp = tmp ^ (n-1);
        matrix Ans;
        Ans.a[1][1]=1;
        Ans = Ans*tmp;
        ll tmp1 = Ans.a[1][1];
        printf("%lld\n",fast(p,tmp1+Mod,q)%q);
    }
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章