Rikka with Prefix Sum(組合數學)
阿新 • • 發佈:2018-08-21
時間 分享圖片 ima top long pla res hang nal
For example, given an array A of length n and m queries. Each query gives an interval [l,r] and you need to calculate . How to solve this problem in O(n+m)? We can calculate the prefix sum array B in which Bi is equal to . And for each query, the answer is Br-Bl-1.
Since Rikka is interested in this powerful trick, she sets a simple task about Prefix Sum for you:
Given two integers n,m, Rikka constructs an array A of length n which is initialized by Ai = 0. And then she makes m operations on it.
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 . Intput: For each testcase, the first line contains two integers n,m(1 ≤ n,m ≤ 10^5)
And then m lines follow, each line describes an operation(1 ≤ L ≤ R≤ n, 0 ≤ w ≤ 10^9).
The input guarantees that for each testcase, there are at most 500 operations of type 3.
Rikka with Prefix Sum
題目描述
Prefix Sum is a useful trick in data structure problems.For example, given an array A of length n and m queries. Each query gives an interval [l,r] and you need to calculate . How to solve this problem in O(n+m)? We can calculate the prefix sum array B in which Bi is equal to
Since Rikka is interested in this powerful trick, she sets a simple task about Prefix Sum for you:
Given two integers n,m, Rikka constructs an array A of length n which is initialized by Ai = 0. And then she makes m operations on it.
There are three types of operations:
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 . Intput:
The first line contains a single number t(1≤ t ≤ 3), the number of the testcases.
And then m lines follow, each line describes an operation(1 ≤ L ≤ R≤ n, 0 ≤ w ≤ 10^9).
The input guarantees that for each testcase, there are at most 500 operations of type 3.
output:
For each query, output a single line with a single integer, the answer modulo 998244353.
test:
Intput:
1
100000 7
1 1 3 1
2
3 2333 6666
2
3 2333 6666
2
3 2333 6666
output
13002
58489497
12043005
中文題意:給定一個序列A,長度最長為100000,初始值為0,現在有三種操作:
1.對區間[l,r]中所有的數都加上一個值。
2.對整個序列求一次前綴和。
3.詢問[l,r]區間內所有a的和。
現在對1,0,0,0求3次前綴和得到下圖
可以發現(1,1)對右下角的點的貢獻是
接下來我們定義一個變量now記錄數組了進行了幾次求數組前綴和也就是題目的2號操作。
對於操作1,在[l,r]區間內每個數增加w。
相當於在上次進行2號操作前,在點 L 增加w,在點 R+1 減少w。
例如:在3到5號位置增加1
序號 1 2 3 4 5 6 7 8 9
now 0 0 1 1 1 0 0 0 0 求前綴和後
now-1 0 0 1 0 0 -1 0 0 0 求前綴和前
對於詢問的話只要求下次求完前綴和 (位置 R 的值) - (位置 L-1 的值)
對於進行前綴和操作只要將now++即可
具體操作看代碼
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 typedef long long ll; 6 const int maxn = 410000,mod=998244353; 7 struct Stack 8 { 9 ll lie,time,value; 10 } st[maxn]; 11 ll fac[maxn+10],ifac[maxn+10],top; 12 13 ll quick_pow(ll a,ll b) 14 { 15 ll ans=1; 16 while(b) 17 { 18 if(b&1) 19 ans=1ll*ans*a%mod; 20 a=1ll*a*a%mod; 21 b>>=1; 22 } 23 return ans; 24 } 25 26 void init() 27 { 28 fac[0]=1; 29 for(int i=1; i<=maxn; i++) 30 fac[i]=1ll*fac[i-1]*i%mod; 31 ifac[maxn]=quick_pow(fac[maxn],mod-2); 32 for(int i=maxn-1; i>=0; i--) 33 ifac[i]=1ll*ifac[i+1]*(i+1)%mod; 34 } 35 36 ll C(ll n,ll m) 37 { 38 return 1ll*fac[n]*ifac[m]%mod*ifac[n-m]%mod; 39 } 40 41 inline ll solve(ll x,ll now) 42 { 43 if(x==0)return 0; 44 45 ll sum = 0; 46 for(int i=0; i<top; i++) ///計算每個更新對點的貢獻值 47 { 48 49 if(st[i].lie>x)continue; 50 ll lie = st[i].lie; 51 ll per = st[i].time; 52 ll value = st[i].value; 53 54 ll aa = x-lie + now-per -1; 55 ll bb = now-per -1; 56 57 sum = (sum + value*C(aa,bb)%mod)%mod; 58 } 59 return sum; 60 } 61 62 int main() 63 { 64 init(); ///預處理階乘和逆元將計算組合數的時間復雜度降為O(1) 65 ll t,n,m,op; 66 scanf("%lld",&t); 67 while(t--) 68 { 69 scanf("%lld%lld",&n,&m); 70 ll now = 1,l,r,value; 71 top = 0; 72 while(m--) 73 { 74 scanf("%lld",&op); 75 if(op==1) 76 { 77 scanf("%lld%lld%lld",&l,&r,&value); 78 st[top].value = value%mod,st[top].time=now-1,st[top].lie=l; 79 top++; 80 st[top].value =(mod-value)%mod,st[top].time=now-1,st[top].lie=r+1; 81 top++; 82 ///將更新存入數組 83 } 84 else if(op==2) 85 { 86 now++; 87 } 88 else 89 { 90 scanf("%lld%lld",&l,&r); 91 ll ans = solve(r,now+1)-solve(l-1,now+1); 92 ans = (ans+mod)%mod; 93 printf("%lld\n",ans); 94 } 95 } 96 } 97 return 0; 98 }View Code
Rikka with Prefix Sum(組合數學)