Newcoder 148 D.Rikka with Prefix Sum(組合數學)
阿新 • • 發佈:2018-12-11
Description
給出一個長度為的序列,初始為,有次操作,操作分三種:
區間均加上
把變成其字首和序列
查詢區間和
Input
第一行一整數表示用例組數,每組用例首先輸入兩個整數表示序列長度和運算元,之後行每行一個操作,保證操作不超過次
Output
對於每個操作,輸出區間和,結果模
Sample Input
1 100000 7 1 1 3 1 2 3 2333 6666 2 3 2333 6666 2 3 2333 6666
Sample Output
13002 58489497 12043005
Solution
對序列求次字首和後,位置原始值對操作後的位置值的貢獻為,注意到區間加操作即為兩個單點修改後求字首和的操作,而查詢操作即為做完字首和後查詢兩個位置的值做差,故對於每次查詢操作,遍歷之前所有修改操作,統計修改操作的單點值對當前查詢單點值的貢獻即可,時間複雜度
Code
#include<cstdio> using namespace std; typedef long long ll; #define maxn 100005 #define mod 998244353 int mul(int x,int y) { ll z=1ll*x*y; return z-z/mod*mod; } int add(int x,int y) { x+=y; if(x>=mod)x-=mod; return x; } int inv[2*maxn],fact[2*maxn]; void init(int n=2e5) { inv[1]=1; for(int i=2;i<=n;i++)inv[i]=mul(mod-mod/i,inv[mod%i]); inv[0]=1; for(int i=1;i<=n;i++)inv[i]=mul(inv[i-1],inv[i]); fact[0]=1; for(int i=1;i<=n;i++)fact[i]=mul(i,fact[i-1]); } int C(int n,int m) { return mul(fact[n],mul(inv[m],inv[n-m])); } int Solve(int x,int y,int z,int w) { if(x==y)return w; if(z==0||y<x)return 0; return mul(w,C(y-x+z-1,z-1)); } struct Query { int op,l,r,w; }q[maxn]; int T,n,m; int main() { init(); scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { scanf("%d",&q[i].op); if(q[i].op==1) { scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].w); q[i].w%=mod; } else if(q[i].op==3) { scanf("%d%d",&q[i].l,&q[i].r); int x=2,A=0,B=0; for(int j=i-1;j>=1;j--) if(q[j].op==2)x++; else if(q[j].op==1) { A=add(A,Solve(q[j].l,q[i].l-1,x,q[j].w)); A=add(A,Solve(q[j].r+1,q[i].l-1,x,mod-q[j].w)); B=add(B,Solve(q[j].l,q[i].r,x,q[j].w)); B=add(B,Solve(q[j].r+1,q[i].r,x,mod-q[j].w)); } printf("%d\n",add(B,mod-A)); } } } return 0; }