题意:
n的数组m次操作
- 1 L R W : L~R的数加上W
- 2 : 原数组变成这个数组的前缀数组
- 3 L R : 求L~R的区间和
输入描述:
The first line contains a single number t(1≤ t ≤ 3), the number of the testcases.For each testcase, the first line contains two integers n,m(1 ≤ n,m ≤ 105). And then m lines follow, each line describes an operation(1 ≤ L ≤ R≤ n, 0 ≤ w ≤ 109). The input guarantees that for each testcase, there are at most 500 operations of type 3.
输出描述:
For each query, output a single line with a single integer, the answer modulo 998244353.
解析:
因为3操作的数量只有500,所以时间的分配应该是num(1,2)*num(3)即O(m*500)
分析每个操作一对答案的贡献: 首先,这个矩阵的 (设为 )代表操作二 次后操作一对L+a-1的位置的贡献(L为这次操作一的左边界) 显然,对于L~R的区间内的数,有 显然,R+1后面的数计算起来非常麻烦(我推了半天推出来了结果100%TLE) 那么我们可以换一种思路,把 变成 + ,就可以不用考虑后面的复杂情况了 |
然后就是对一个区间的贡献和了
所以就做出来了,对于每一个操作三,遍历之前的所有操作一(当然要记下到那个时候的操作2的次数,再用总次数减去那个次数,就是这次操作一到操作三的操作二的次数)
代码:
D read(){ D ans=0; char last=' ',ch=getchar();
while(ch<'0' || ch>'9')last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
}
const int N=200000;
const F pi=acos(-1);
const D mod=998244353;
const F _e=2.718281828459045;
/*快速幂*/
D swift(D a,D b){
D ans=1ll;
while(b){
if(b%2)ans=ans*a%mod;
b>>=1;
a=a*a%mod;
}return ans;
}
D inv(D a){return swift(a,mod-2);}//费马小定理
/*预处理阶乘*/
D fac[N+9];
D inv_fac[N+9];
void init_fac(){
fac[0]=fac[1]=1ll;
for(int i=2;i<=N;i++)fac[i]=fac[i-1]*i%mod;
//预处理阶乘逆元
inv_fac[N]=swift(fac[N],mod-2);//费马小定理求 N!的逆元
for(D i=N-1;i>=1;i--) inv_fac[i]=(inv_fac[i+1]*(i+1))%mod;
inv_fac[0]=1;
}
D A(D a,D b){//排列数 a下
if(b>a||b<0)return 0;
return fac[a]*inv_fac[a-b]%mod;
}
D C(D a,D b){//组合数 a下
if(b>a||b<0)return 0;
return fac[a]*inv_fac[a-b]%mod*inv_fac[b]%mod;
}
D arr[200009];
int preq[200009];
int numq;int now;
int l[200009],r[200009];D v[200009];
D Csum(D l,D r,D v,D q){
if(l>r)return 0;
D n=r-l+1;
D ans=C(q+n-1,q)*v%mod;
ans=(ans+mod)%mod;
return ans;
}
D query(D R){
D ans=0;
for(int i=1;i<=now;i++){
int q=numq-preq[i]+1;//因为组合数的和是q变成q+1,所以在这里先加上
if(l[i]>R)continue;
if(r[i]<=R)
ans=(ans+Csum(l[i],R,v[i],q))%mod,//C(q,q)+C(q+1,q)+...C(q+n1-1,q)
ans=(ans+Csum(r[i]+1,R,-v[i],q)+mod)%mod;
else
ans=(ans+Csum(l[i],R,v[i],q)+mod)%mod;
}
return ans;
}
void solve(int L,int R){
printf("%lld\n",(query(R)-query(L-1)+mod)%mod);
}
int main(){
init_fac();
int t=read();
while(t--){
now=0;
numq=0;
int n=read(),m=read();
while(m--){
int f=read();
if(f==1){
l[++now]=read(),r[now]=read();v[now]=read();
preq[now]=numq;
}
else if(f==2){
numq++;
}
else{
int l=read(),r=read();
solve(l,r);
}
}
}
}