题面
题解
记 p = 998244353 p=998244353 p=998244353,那么 a p − 1 ≡ 1 ( m o d p ) a^{p-1}\equiv 1\pmod p ap−1≡1(modp)。( gcd ( a , p ) = 1 \gcd(a,p)=1 gcd(a,p)=1)
那么 a b ≡ a b m o d ( p − 1 ) ( m o d p ) a^b\equiv a^{b\bmod (p-1)}\pmod p ab≡abmod(p−1)(modp)。
题目的操作相当于每次把一个数的指数乘上 2 2 2,那么每个数都能表示成 a 2 x a^{2^x} a2x 的形式。(初始时 x = 0 x=0 x=0)
打表找 2 x m o d 998244352 2^x\bmod 998244352 2xmod998244352 的循环节,发现从 2 23 2^{23} 223 开始,每 24 24 24 位循环一次,即 2 23 ≡ 2 47 ( m o d p − 1 ) , 2 24 ≡ 2 48 ( m o d p − 1 ) , ⋯ 2^{23}\equiv 2^{47}\pmod{p-1},2^{24}\equiv 2^{48}\pmod{p-1},\cdots 223≡247(modp−1),224≡248(modp−1),⋯。
那么对于每个数的修改,前 23 23 23 次我们暴力跑,后面的我们就在线段树上对于每一个区间维护一个大小为 24 24 24 的环,修改一次我们就把环转一格即可。
代码如下:
#include<bits/stdc++.h>
#define N 200010
using namespace std;
namespace modular
{
const int mod=998244353;
inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
inline int mul(int x,int y){return 1ll*x*y%mod;}
}using namespace modular;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^'0');
ch=getchar();
}
return x*f;
}
int n,q,a[N],tim[N];
int f[N<<2][24];
int lazy[N<<2];
bool ok[N<<2];
void up(int k)
{
for(int i=0;i<24;i++) f[k][i]=add(f[k<<1][i],f[k<<1|1][i]);
ok[k]=(ok[k<<1]&ok[k<<1|1]);
}
void build(int k,int l,int r)
{
if(l==r)
{
f[k][0]=read();
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
up(k);
}
void turn(int k,int tim)
{
static int b[24];
for(int i=0;i<24;i++) b[i]=f[k][i];
for(int i=0;i<24;i++) f[k][i]=b[(i+tim)%24];
}
void downn(int k,int tim)
{
turn(k,tim);
lazy[k]=(lazy[k]+tim)%24;
}
void down(int k)
{
if(lazy[k])
{
downn(k<<1,lazy[k]);
downn(k<<1|1,lazy[k]);
lazy[k]=0;
}
}
void update(int k,int l,int r,int ql,int qr)
{
if(ql<=l&&r<=qr&&ok[k])
{
downn(k,1);
return;
}
if(l==r)
{
f[k][0]=mul(f[k][0],f[k][0]);
tim[l]++;
if(tim[l]==23)
{
ok[k]=1;
for(int i=1;i<24;i++)
f[k][i]=mul(f[k][i-1],f[k][i-1]);
}
return;
}
down(k);
int mid=(l+r)>>1;
if(ql<=mid) update(k<<1,l,mid,ql,qr);
if(qr>mid) update(k<<1|1,mid+1,r,ql,qr);
up(k);
}
int query(int k,int l,int r,int ql,int qr)
{
if(ql<=l&&r<=qr) return f[k][0];
down(k);
int mid=(l+r)>>1,ans=0;
if(ql<=mid) ans=add(ans,query(k<<1,l,mid,ql,qr));
if(qr>mid) ans=add(ans,query(k<<1|1,mid+1,r,ql,qr));
return ans;
}
int main()
{
n=read(),q=read();
build(1,1,n);
while(q--)
{
int opt=read(),l=read(),r=read();
if(opt==1) update(1,1,n,l,r);
else printf("%d\n",query(1,1,n,l,r));
}
return 0;
}
/*
3 3
1 2 3
2 1 3
1 1 2
2 2 3
*/