[六省联考2017]相逢是问候

Informatik verbindet dich und mich

Informatik verbindet dich und mich

扩展欧拉定理+线段树。

Informatik verbindet dich und mich

由扩展欧拉定理得,cc...最终上面的指数必定变成1.(不会打这个东西。。。)

最多取log次就会变成1,然后就没用了。

我们每次算的时候再快速幂的话时间复杂度是貌似不能过的。好像是nlog^3n

至少我加了N发卡常还是过不了。

但是我们通过题解发现实际上每次快速幂的底数都是一样的,指数也差不多,就可以预处理。

但是mod的最大值可能达到1e8.

所以我们预处理1-1e4的,然后再预处理c1e4的1-1e4的。

最后时间复杂度就去了一个log,不用卡常也过了。

#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
using namespace std;
const int N=100005;
inline char gc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
//#define gc getchar
inline int rd() {
    register int x=0;register char ch=gc();
    while(!isdigit(ch)) ch=gc();
    while(isdigit(ch)) {x=x*10ll+(ch^48);ch=gc();}
    return x;
}
struct Segtree{
   int sum;int  l,r;short tag;
}t[N<<2];
int a[N],phi[N],n,m,p,c,lim,l,r,low_er[50005][105],high_er[50005][105],f[50005][105];
bool flag;
int ksm(int z,int mod) {
    if(z<=10000) return low_er[z][mod];
    return 1ll*high_er[z/10000][mod]*low_er[z%10000][mod]%phi[mod];
}
int ksm(long long d,int z,int mod) {
    long long res=1ll;
    while(z) {
        if(z&1) res=res*d;
        d=d*d;
        if(res>=mod) res%=mod;
        if(d>=mod) d%=mod;
        z>>=1;
    }
    return res;
}
int work(int d,int z) {
    int res=d;
    if(res>=phi[z]) res=res%phi[z]+phi[z];
    while(z) {
        flag=0;
        res=ksm(res,phi[z-1]);
        if(flag) res+=phi[z-1];
        z--;
    }
    return res;
}
#define ls (cur<<1)
#define rs (cur<<1|1)
#define mid (l+r>>1)
void build(int l,int r,int cur){
    t[cur].l=l,t[cur].r=r;
    if(l==r) {
        t[cur].sum=a[l];
        return;
    }
    build(l,mid,ls);
    build(mid+1,r,rs);
    t[cur].sum=(t[ls].sum+t[rs].sum)%p;
}
void update(int cur) {
    if(t[cur].tag>=lim) return;
    if(l>t[cur].r||r<t[cur].l) return;
    if(t[cur].l==t[cur].r) {
        t[cur].tag++;
        t[cur].sum=f[t[cur].l][t[cur].tag];
        return;
    }
    update(ls);
    update(rs);
    t[cur].sum=(t[ls].sum+t[rs].sum)%p;
    t[cur].tag=min(t[ls].tag,t[rs].tag);
}
long long query(int cur) {
    if(l>t[cur].r||r<t[cur].l) return 0;
    if(l<=t[cur].l&&t[cur].r<=r) return t[cur].sum;
    return (query(ls)+query(rs))%p;
}
#undef ls
#undef rs
#undef mid
int getphi(long long x) {
    int res=x,sq=sqrt(x);
    for(int i=2;i<=sq;i++) {
        if(!(x%i)) {
            while(!(x%i)) x/=i;
            res=res/i*(i-1);
        }
    }
    if(x-1) res=res/x*(x-1);
    return res;
}
int cal(int x,int num,int d) {
    if(!num) return x%phi[d];
    int t=cal(x,num-1,d+1);
    if(pow(c,num-1)*x>=phi[d+1]) t+=phi[d+1];
    return ksm(t,d);
}
void pre() {
    for(int i=0;i<=10000;i++) {
        for(int j=0;j<=lim;j++) {
            low_er[i][j]=ksm(c,i,phi[j]);
            high_er[i][j]=ksm(ksm(c,10000,phi[j]),i,phi[j]);
        }
    }
    for(int i=1;i<=n;i++) {
        if(!a[i]) {
            f[i][1]=1;
            for(int j=2;j<=lim;j++) {
                f[i][j]=cal(1,j-1,0);
            }
        }
        else for(int j=1;j<=lim;j++) f[i][j]=cal(a[i],j,0);
    }
}
signed main() {
    n=rd();m=rd(),p=rd();c=rd();
    phi[0]=p;
    while(phi[lim]^1) lim++,phi[lim]=getphi(phi[lim-1]);
    phi[++lim]=1;
    for(int i=1;i<=n;i++) a[i]=rd();
    pre();
    build(1,n,1);
    int opt;
    while(m--) {
        opt=rd();l=rd();r=rd();
        switch (opt) {
            case 0: {update(1);break;}
            case 1: {printf("%d
",query(1));break;}
        }
    }
    return 0;
}
相逢是问候
我是咸鱼。转载博客请征得博主同意Orz
原文地址:https://www.cnblogs.com/sdfzhsz/p/9748168.html