降冪算法

歐拉降冪公式

aaba≡ab%φ(p)φ(p)+φ(p)φ(p)(modp)(modp)b>φ(p)(b>φ(p))

可以把大指數轉化成不超過φ(p)φ(p)的指數。
注意,這裏不要求a,p互質。
注意,這裏不要求a,p互質。
注意,這裏不要求a,p互質。(重要的事情說三遍!!!)

證明就不說啦,太菜了…

費馬小定理

首先p是一個質數,aapa(modp)≡a(modp)。若gcd(a,p)=1時,aap-11(modp)≡1(modp);若gcd(a,p)=p,aap-10(modp)≡0(modp)
可以看出費馬小定理是歐拉的特殊情況,即p是質數,φ(p)=p1φ(p)=p-1。


傳送門:Days passing

題意: 已知當前是周幾,求NM(1<=N<10N^M(1<=N<1010000,6<=M<10000,M6),6<=M<10000,M是6的整數倍)天后是周幾。
解析: 根據費馬小定理:7是質數,
如果N是7的倍數,NMN^M%7=0,週數不變,
如果N不是7的倍數,NMN^M%7=1,週數向前一天。
代碼:

#include<bits/stdc++.h>
using namespace std;
char N[10010];
string str;
int n=0,m;
int main(){
    cin>>str;
    scanf("%s",N+1);
    scanf("%d",&m);
    int len=strlen(N+1);
    for(int i=1;i<=len;i++){
        n=(n*10+N[i]-'0')%7;
    }
    if(n==0) cout<<str<<endl;
    else {
        if(str=="Mon") cout<<"Tue";
        else if(str=="Tue") cout<<"Wed";
        else if(str=="Wed") cout<<"Thu"<<endl;
        else if(str=="Thu") cout<<"Fri"<<endl;
        else if(str=="Fri") cout<<"Sat"<<endl;
        else if(str=="Sat") cout<<"Sun"<<endl;
        else if(str=="Sun") cout<<"Mon"<<endl;
    }
    return 0;
}

傳送門:sum

題意: 由1個數,2個數,3個數,…,n個數相加等於N(N爲大整數)的不同情況有多少種。
解析: 用擋板法,假設N=3,有:1 1 1,有兩個間隙。一個數時不需要加擋板爲C(2,0),兩個數時加一個擋板爲C(2,1),三個數時加兩個擋板爲C(2,2).那麼其實就是求:C(N-1,0)+C(N-1,1)+C(N-1,2)+…+C(N-1,N-1)=2N-1
答案mod 1e9+7。那麼就對N進行大整數模擬取模1e9+6,最後再-1。再用快速冪即的答案。
代碼:

#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
const int mod=1e9+7;
char s[100010];
int N[100010];
int main(){
    while(~scanf("%s",s+1)){
        int len=strlen(s+1);
        long long sum=0;
        for(int i=1;i<=len;++i){
            sum=(sum*10+s[i]-'0')%(mod-1);
        }
        sum--;
        long long ans=1,tmp=2;
        while(sum){
            if(sum&1) ans=(ans*tmp)%mod;
            tmp=(tmp*tmp)%mod;
            sum/=2;
        }
        cout<<ans<<endl;
    }
    return 0;
}

傳送門:上帝與集合的正確用法

題意:在這裏插入圖片描述
解析: 考慮歐拉降冪,f(p ) =22%oula(p )+p%p ,f(oula(p ))=22%oula(oula(p ) )+oula(p )%oula(p ),可以看出這是一個遞推式,如果直接遞推時間複雜度是否可行?
p到oula(p ) =p*(1-p/p1)…*(1-p/pn)。當p是偶數,一定有p1=2,會乘上1/2;當p是奇數,oula(p )一定是偶數,因爲它包含奇數質因子1-(1/奇數)會產生偶因子。
代碼:

#include<bits/stdc++.h>
#include<algorithm>
using namespace std;
int oula(int n){
    int rea=n;
    for(int i=2;i*i<=n;i++){
        if(n%i==0){
            rea=rea-rea/i;
            do{
                n/=i;
            }while(n%i==0);
        }
    }
    if(n>1) rea=rea-rea/n;
    return rea;
}
int qp(int a,int b,int p){
    int ans=1,tmp=a;
    while(b){
        if(b&1) ans=(1ll*ans*tmp)%p;
        tmp=(1ll*tmp*tmp)%p;
        b/=2;
    }
    return ans;
}
map<int,int> mmp;
int f(int p){
    if(mmp[p]!=0) return mmp[p];
    int ol=oula(p);
    if(p==1||p==2){
        return 0;
    }
    int t=qp(2,f(ol)+ol,p);
    mmp[p]=t;
    return t;
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        int p;
        scanf("%d",&p);
        printf("%d\n",f(p));
    }
    return 0;
}

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