题目:https://www.nowcoder.com/acm/contest/148/D
题意:
给一个数组a,一开始的值全为0。一共有三个操作:
1. 对区间[L,R]的每个数都加上w。
2. 将数组a用其前缀和数组代替。
3. 将询问区间[L,R]的区间和。
题解:大佬
/**
参考大佬题解:http://www.cnblogs.com/tetew/p/9504595.html
0 1 2 3 4 5 6 (下标)
0 0 1 -1 0 0 0 0 (第0层)
1 0 (1) 0 0 0 0 0 (原数组 , 使a1 = 1)
2 0 1 1 1 1 1 1
3 0 1 2 3 4 5 6
4 0 1 3 6 10 15 21
5
.
.
--- x层是 x+1 层的差分。
---原来的序列的l-r区间+w,其实就是在它的差分序列l处+w,r+1处-w.
---所以如果在(i,j)点+w,那么(x,y)点的系数为C(x-i+y-j-1,x-i-1).
---求第x层的 sum(l,r) 相当于求 第 x+1 层的 a[r] - a[l-1].
**/
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long int ll;
const ll Mod = 998244353;
const int maxn = 2e5;
int n,m;
int qx[maxn+5],qy[maxn+5];
ll qw[maxn+5];
int nowx,q_cnt;
//---------C(a,b)代码。
ll fac[maxn+5],inv[maxn+5];
const ll MOD = Mod;
ll powi(ll a, ll b)
{
ll c = 1;
for (; b; b >>= 1, a = 1ll * a * a % MOD)
if (b & 1) c = 1ll * c * a % MOD;
return c;
}
void initC()
{
int mx = maxn;
fac[0] = 1; for (int i = 1; i <= mx; ++ i) fac[i] = 1ll * fac[i - 1] * i % MOD;
inv[mx] = powi(fac[mx], MOD - 2); for (int i = mx - 1; ~i; -- i) inv[i] = 1ll * inv[i + 1] * (i + 1) % MOD;
}
ll C(int a, int b)
{
return 1ll * fac[a] * inv[b] % MOD * inv[a - b] % MOD;
}
//-----------------
ll solve(int x,int y)
{
ll sum = 0;
for(int i=1;i<=q_cnt;i++)
{
if(qx[i]<=x&&qy[i]<=y)
{
sum = (sum + C( x-qx[i]+y-qy[i]-1, x-qx[i]-1 )*qw[i]%Mod + Mod)%Mod;
}
}
return sum;
}
int main()
{
int T;
initC();
scanf("%d",&T);
while(T--)
{
scanf("%d %d",&n,&m);
nowx = 1, q_cnt = 0;
for(int i=1;i<=m;i++)
{
int opt,l,r,w;
scanf("%d",&opt);
if(opt==1)
{
scanf("%d %d %d",&l,&r,&w);
qx[++q_cnt] = nowx-1, qy[q_cnt] = l, qw[q_cnt] = 1ll*w%Mod;
qx[++q_cnt] = nowx-1, qy[q_cnt] = r+1, qw[q_cnt] = 1ll*(Mod-w)%Mod;
}
if(opt==2) nowx++;
if(opt==3)
{
scanf("%d %d",&l,&r);
printf("%lld\n",( (solve(nowx+1,r) - solve(nowx+1,l-1))%Mod + Mod)%Mod);
}
}
}
return 0;
}