洛谷10月月赛R2-T3-Nephren Ruq Insania

传送门
这个题明显扩展欧拉定理,也就是这个定理:

abmodc=a(bmodϕc)+ϕcmodc
我们可以递归地去做那个式子,一直取phi,再加个快速幂( =ksm=kasumi)就好了。
所以就可以做了。
还有就是这么一直取phi,最多只会取 log2p 次,就会变成1,然后就是:
amod1+ϕ1=0+1=1
就不用继续做下去了。
所以这样的复杂度就是 O(m(query)log2p+m(update)len) 其中len代表修改长度
所以还是会被最后一组数据卡时间。
我们可以发现只有一个修改,而且是加法,所以就可以分块了!
分出块来之后,我们就可以用 O(m(query)log2p+m(update)n) 的时间解决了。
(补充,还要多一个log,还要算上快速幂的复杂度)
代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#define ll long long
using namespace std;
inline int read(){
    int x=0;char ch=' ';int f=1;
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')f=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int phi[20000001];
bool vis[20000001];
int prime[10000001];
int cnt;
inline void getphi(int n){
    phi[0]=1;
    phi[1]=1;
    for(int i=2;i<=n;++i){
        if(!vis[i]){
            prime[++cnt]=i;
            phi[i]=i-1;
        }
        for(int j=1;j<=cnt&&(ll)i*(ll)prime[j]<=n;++j){
            int k=i*prime[j];
            vis[k]=1;
            if(i%prime[j]==0){
                phi[k]=phi[i]*prime[j];
                break;
            }
            else{
                phi[k]=phi[i]*(prime[j]-1);
            }
        }
    }
}
inline ll ksm(ll a,ll n,ll p){
    a%=p;
    ll ans=1;
    while(n){
        if(n&1){
            ans=(ans*a)%p;
        }
        a=(a*a)%p;
        n>>=1;
    }
    return ans;
}
int n,m;
ll a[500001];
ll pp[500001];
ll add[500001];
int l[500001];
int r[500001];
int belong[500001];
int block,tot;
inline void update(int x,int y,int v){
    if(belong[x]==belong[y]){
        for(int i=x;i<=y;++i){
            a[i]+=v;
        }
        return;
    }
    for(int i=x;i<=r[belong[x]];++i){
        a[i]+=v;
    }
    for(int i=l[belong[y]];i<=y;++i){
        a[i]+=v;
    }
    for(int i=belong[x]+1;i<=belong[y]-1;++i){
        add[i]+=v;
    }
    return;
}
int main(){
    n=read();m=read();
    getphi(20000000);
    for(int i=1;i<=n;i++){
        a[i]=read();
    }
    block=sqrt(n);
    tot=n/block;
    if(n%block)tot++;
    for(int i=1;i<=n;++i){
        belong[i]=(i-1)/block+1;
    }
    for(int i=1;i<=tot;++i){
        l[i]=(i-1)*block+1;
        r[i]=i*block;
    }
    while(m--){
        int opt=read(),l=read(),r=read(),p=read();
        if(opt&1){
            update(l,r,p);
        }
        else{
            pp[l]=p;
            for(int i=l+1;i<=r;i++){
                pp[i]=phi[pp[i-1]];
                if(pp[i]==1){
                    r=i;
                    break;
                }
            }
            ll now=1;
            for(int i=r;i>=l;i--){
                now=ksm(a[i]+add[belong[i]],now,pp[i])+pp[i];
            }
            printf("%lld\n",now%p);
        }
    }
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值