题解 P7334【[JRKSJ R1] 吊打】

Link

题意

给出 n,m 表示长为 n 的序列 am 次操作,支持两种操作:

  • 1 l r,对所有 i[l,r],将 aiai
  • 2 l r,对所有 i[l,r],将 aiai2

最后输出 (i=1nai)mod998244353

时间 1s,n,m2×105

思路

Update 2022.4.21:重构全文。

发现区间开方直接拍一个分块上去,参考 P4145。

这里不好维护原数,考虑维护 i 位置上的数被平方的次数 si

操作 1 为区间加。考虑操作 2,散块暴力,整块维护 si 最小值。若 minsi1,直接打区间减 tag,否则若 maxai=1,跳过,否则暴力开方或将 si 减一。

由势能分析,我们知道这部分是 O(nnloglogw) 的。

求出 si 后考虑得出答案,用欧拉定理降幂,预处理一下 2kmod998244352,即可在 O(logp) 时间内求出 ai2si,总时间复杂度为 O(nnloglogw),期望得分 100 分。

我没写代码,dqstz 写了:

#include<bits/stdc++.h>
using namespace std;
const int mx=2e5+5; 
const int mod=998244353;
int a[mx];
int bl[mx],fl[mx],fr[mx];
int s[mx],tag[mx],mn[mx],os[mx];
int pow2[mx];
int n,b,ks;
void init()
{
    int i,j,k,mx;
    b=sqrt(n);
    for(i=1;i-1+b<=n;i+=b)
        fl[++ks]=i,fr[ks]=i-1+b;
    if(i<=n)
        fl[++ks]=i,fr[ks]=n;
    for(i=1;i<=ks;i++)
        for(j=fl[i];j<=fr[i];j++)
            bl[j]=i;
}
int qpow(int a,int p,int mod)
{
    if(p==0) return 1;
    if(p==1) return a;
    long long t=qpow(a,p/2,mod);
    return t*t%mod*qpow(a,p%2,mod)%mod;
}
int read()
{
    int s=0;
    char ch=getchar();
    while(ch<'0'||ch>'9') ch=getchar();
    while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
    return s;
}
void cg(int x)
{
    mn[x]=2e9;
    for(int i=fl[x];i<=fr[x];i++)
        mn[x]=min(mn[x],s[i]+tag[x]);
}
void zk(int x)
{
    for(int i=fl[x];i<=fr[x];i++)
        s[i]+=tag[x];
    tag[x]=0;
}
void add(int l,int r)
{
    if(bl[l]==bl[r])
    {
        zk(bl[l]);
        for(;l<=r;l++)
            s[l]++;
        cg(bl[l-1]);
        return;
    }
    add(l,fr[bl[l]]),add(fl[bl[r]],r);
    int i;
    for(i=bl[l]+1;i<bl[r];i++)
        tag[i]++,mn[i]++;
}
void sqrt(int l,int r)
{
    if(bl[l]==bl[r])
    {
        zk(bl[l]);
        for(;l<=r;l++)
        {
            if(a[l]==1) continue;
            if(s[l]==0) 
            {
                a[l]=sqrt(a[l]);
                os[bl[l]]+=a[l]==1;
            }
            else s[l]--;
        }
        cg(bl[l-1]);    
        return;
    }
    sqrt(l,fr[bl[l]]),sqrt(fl[bl[r]],r);
    for(int i=bl[l]+1;i<bl[r];i++)
    {
        if(os[i]==fr[i]-fl[i]+1) continue;
        if(mn[i]==0)
            sqrt(fl[i],fr[i]);      
        else
            mn[i]--,tag[i]--;   
    }               
}
int main()
{
    int m,i,opt,l,r,sum=0,wz=2e9,qwq;
    n=read(),m=read();
    init();
    pow2[0]=1;
    for(i=1;i<=n;i++)
        a[i]=read();
    for(i=1;i<=m;i++)
    {
        pow2[i]=pow2[i-1]*2;
        if(pow2[i]>=mod-1&&wz==2e9) wz=i;
        pow2[i]%=mod-1;
    }
    while(m--)
    {
        opt=read(),l=read(),r=read();
        if(opt==1) sqrt(l,r);
        else add(l,r);
    }
    for(i=1;i<=ks;i++)
        zk(i);
    for(i=1;i<=n;i++)
    {
        if(a[i]==1)
        {
            sum=(sum+1)%mod;
            continue;
        }
        qwq=pow2[s[i]];
        if(s[i]>=wz) qwq+=mod-1;
        sum=(sum+qpow(a[i],qwq,mod))%mod;   
    }
    cout<<sum%mod;
} 

再见 qwq~

posted @   ffffyc  阅读(14)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示