1. 程式人生 > >Rikka with Prefix Sum(組合數學)

Rikka with Prefix Sum(組合數學)

時間 分享圖片 ima top long pla res hang nal

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 技術分享圖片
. 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:

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 ≤ 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.

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(組合數學)