1. 程式人生 > >小學擴展歐拉定理

小學擴展歐拉定理

continue ini 方法 cstring update click LG href inline

學了一下擴展歐拉定理,不會證,記了個結論,筆記的話,隨便去網上搜一搜吧.
-bzoj3884:上帝與集合的正確用法
無腦板子題額

技術分享圖片
#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long LL;
inline int Pow(int x,int y,int P){
    int ret=1;
    while(y){
        if(y&1)ret=(LL)ret*x%P;
        x=(LL)x*x%P,y>>=1
; } return ret; } inline int Phi(int x){ if(x==1)return 1; int i,ret=x; for(i=2;i*i<=x;++i) if(x%i==0){ ret=ret/i*(i-1); while(x%i==0)x/=i; } if(x!=1)ret=ret/x*(x-1); return ret; } inline int Power(int P){ if(P==1)return
0; int phi=Phi(P); return Pow(2,Power(phi)+phi,P); } int main(){ int T,P; scanf("%d",&T); while(T--){ scanf("%d",&P); printf("%d\n",Power(P)); } return 0; }
Kod

-bzoj4869:[Shoi2017]相逢是問候
見https://blog.sengxian.com/solutions/bzoj-4869
這道題的小細節還是比較坑的啊,比如:1.多加一個1;2.判斷上一層和上一層模數的大小關系.(網上的人大概都是判0或者試乘,我寫的是試乘,因為我不會證明判0的正確性,而且也看不懂除了試乘以外的方法)(我的試乘比較蠢,但是他的正確性我應該是證出來了)

技術分享圖片
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long LL;
const int A=50;
const int N=50010;
const int F=1<<15;
const int oo=100000000;
int n,m,k,P,cmp,hp,phi[A],a[N],mi1[A][F+10],mi2[A][F+10];
inline int Pow(int x,int y,int P,int cur){
    int ret=(LL)mi1[cur][y&(F-1)]*mi2[cur][y>>15]%P;
    return ret;
}
inline int Pow_(int x,int y,int P,int cur){
    if(y>=cmp)return Pow(x,y,P,cur);
    LL ret=1;
    int i;
    for(i=1;i<=y;++i){
        ret*=x;
        if(ret>=P)return Pow(x,y,P,cur);
    }
    return ret+oo;
}
inline int Phi(int x){
  if(x==1)return 1;
  int i,ret=x;
  for(i=2;i*i<=x;++i)
    if(x%i==0){
      ret=ret/i*(i-1);
      while(x%i==0)x/=i;
    }
    if(x!=1)ret=ret/x*(x-1);
  return ret;
}
inline int Power(int rest,int aim,int P,int cur){
    if(!rest)return aim<P?aim+oo:aim%P;
    int ret=Power(rest-1,aim,phi[cur+1],cur+1);
    if(ret<oo)return Pow(k,ret+phi[cur+1],P,cur);
    return Pow_(k,ret-oo,P,cur);
}
struct Segment_Tree{
    Segment_Tree *ch[2];
    int hp,sum;
    inline void pushup(){
        sum=(ch[0]->sum+ch[1]->sum)%P;
        hp=ch[0]->hp+ch[1]->hp;
    }
}*root,node[N<<2];
int sz;
#define newnode (node+(sz++))
#define mid ((l+r)>>1)
inline void build(Segment_Tree *&p,int l,int r){
    p=newnode;
    if(l==r){
        p->hp=hp;
        p->sum=a[l];
        return;
    }
    build(p->ch[0],l,mid);
    build(p->ch[1],mid+1,r);
    p->pushup();
}
inline void dfs(Segment_Tree *p,int l,int r){
    if(!p->hp)return;
    if(l==r){
        --p->hp;
        p->sum=k==1?1:Power(hp-p->hp,a[l],P,0);
        if(p->sum>=oo)p->sum-=oo;
        return;
    }
    dfs(p->ch[0],l,mid);
    dfs(p->ch[1],mid+1,r);
    p->pushup();
}
inline void update(Segment_Tree *p,int l,int r,int z,int y){
    if(z<=l&&r<=y){
        dfs(p,l,r);
        return;
    }
    if(z<=mid)update(p->ch[0],l,mid,z,y);
    if(mid<y)update(p->ch[1],mid+1,r,z,y);
    p->pushup();
}
inline int query(Segment_Tree *p,int l,int r,int z,int y){
    if(z<=l&&r<=y)return p->sum;
    int ret=0;
    if(z<=mid)ret+=query(p->ch[0],l,mid,z,y);
    if(mid<y)ret+=query(p->ch[1],mid+1,r,z,y);
    return ret%P;
}
inline void Init(){
    scanf("%d%d%d%d",&n,&m,&P,&k);
    int cur=P,step=-1,i,j;
    while(true){
        phi[++step]=cur;
        if(cur==1)break;
        cur=Phi(cur);
    }
    hp=step;
    phi[++hp]=1;
    for(i=0;i<=hp;++i){
        mi1[i][0]=1%phi[i];
        for(j=1;j<F;++j)
            mi1[i][j]=(LL)mi1[i][j-1]*k%phi[i];
        cur=(LL)mi1[i][F-1]*k%phi[i];
        mi2[i][0]=1%phi[i];
        for(j=1;j<F;++j)
            mi2[i][j]=(LL)mi2[i][j-1]*cur%phi[i];
    }
    cmp=k==1?0:std::ceil(std::log(P)/std::log(k));
    for(i=1;i<=n;++i)
        scanf("%d",&a[i]);
    build(root,1,n);
}
inline void Work(){
    int opt,l,r;
    while(m--){
        scanf("%d%d%d",&opt,&l,&r);
        if(opt){
            printf("%d\n",query(root,1,n,l,r));
            continue;
        }
        update(root,1,n,l,r);
    }
}
int main(){
    Init();
    Work();
    return 0;
}
Kod

小學擴展歐拉定理