牛客多校第十场D(前缀和与组合数)
题意:长度为n的序列,初始都是0,维护3个操作:
There are three types of operations:
1. 1 L R w, for each index i ∈ [L,R], change Ai to Ai + w.
2. 2, change A to its prefix sum array. i.e., let A' be a back-up of A, for each i ∈ [1,n], change Ai to .
3. 3 L R, query for the interval sum .
题解:
补充:j位置在i位置后面,组合数的得来类似走网格的方案数
下个结论借助前缀和差分的思想
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cstdlib> 5 #include<sstream> 6 #include<ctime> 7 #include<cassert> 8 #include<iostream> 9 #include<vector> 10 using namespace std; 11 typedef long long ll; 12 const ll mod = 998244353; 13 const int N=200005; 14 ll fact[N], ifact[N], inv[N]; 15 16 void init() { 17 fact[0] = 1; 18 for(int i=1;i<=N-1;i++) fact[i] = fact[i-1] * i % mod; 19 inv[1] = 1; 20 for (int i = 2; i <= N-1; i++) 21 inv[i] = (mod - mod / i) * inv[mod % i] % mod; 22 ifact[0] = 1; 23 for(int i=1;i<=N-1;i++) ifact[i] = ifact[i-1] * inv[i] % mod; 24 } 25 ll C(ll a,ll b) 26 { 27 if(b>a||a<0||b<0) return 0; 28 return (fact[a]*ifact[b]%mod)*ifact[a-b]%mod; 29 } 30 struct node{ 31 int tt,pos; 32 ll w; 33 }; 34 35 int main() 36 { 37 int t; 38 init(); 39 cin>>t; 40 while(t--) 41 { 42 int n,m; 43 cin>>n>>m; 44 int tot=0; 45 vector<node>vt; 46 while(m--) 47 { 48 int op,l,r; 49 ll w; 50 scanf("%d",&op); 51 if(op==1) 52 { scanf("%d%d%lld",&l,&r,&w); 53 int x=tot-1; 54 55 vt.push_back((node){x,l,w}); 56 vt.push_back((node){x,r+1,-w}); 57 } 58 else if(op==2) tot++; 59 else 60 { 61 scanf("%d%d",&l,&r); 62 63 ll suml=0,sumr=0; 64 int x=tot+1,l2=vt.size(); 65 66 for(int i=0;i<l2;i++) 67 { 68 if(vt[i].pos<=l-1) 69 { 70 suml+=C(x-vt[i].tt+l-1-vt[i].pos-1,x-vt[i].tt-1)*vt[i].w%mod; 71 suml%=mod; 72 } 73 if(vt[i].pos<=r) 74 { 75 sumr+=C(x-vt[i].tt+r-vt[i].pos-1,x-vt[i].tt-1)*vt[i].w%mod; 76 sumr%=mod; 77 } 78 } 79 printf("%lld\n",(sumr-suml+2ll*mod)%mod); 80 81 } 82 } 83 } 84 } 85