链接:https://www.nowcoder.com/acm/contest/148/D
来源:牛客网
题目描述
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 .
输入描述:
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 ≤ 105).
And then m lines follow, each line describes an operation(1 ≤ L ≤ R≤ n, 0 ≤ w ≤ 109).
The input guarantees that for each testcase, there are at most 500 operations of type 3.
输出描述:
For each query, output a single line with a single integer, the answer modulo 998244353.
示例1
输入
1
100000 7
1 1 3 1
2
3 2333 6666
2
3 2333 6666
2
3 2333 6666
输出
13002
58489497
12043005
题意 : 给你一个长度为 n 的序列,初始元素均为 0 , 有 3 种操作, 1 是给序列的某一个区间加上同一个元素, 2 是将此序列变为它的前缀和序列, 3 是求序列某一个区间的和 ,数据保证 操作3 的次数不多于 500 次
思路分析 : 这题想了好久才勉强有点思路,挺不错的一道题目 , 可以这样想,当我们在某一个位置上增加一个数时,再求上几次前缀和,画个表写出来,会发现这其实就是一个斜着的杨辉三角,找到其是哪一行哪一列,直接公式就可以算出来, C(n-1,m-1)。操作 2 的话就累加,操作3的话就进行一次求和计算即可。
代码示例 :
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll maxn = 2e5+5;
const ll mod = 998244353;
ll n, m;
struct node{
ll tt, pos, w;
}a[maxn];
ll cnt;
ll pp[maxn], inv[maxn];
ll qw(ll x, ll n){
ll res = 1;
while(n > 0){
if (n & 1) res = res * x % mod;
x = x * x % mod;
n >>= 1;
}
return res%mod;
}
void init() {
pp[0] = 1;
for(ll i = 1; i <= 200000; i++) {
pp[i] = (pp[i-1]*i)%mod;
inv[i] = qw(pp[i], mod-2);
}
inv[0] = inv[1];
}
ll C(ll n, ll m){
ll ans = pp[n]*inv[m]%mod*inv[n-m]%mod;
return ans%mod;
}
ll query(ll pos, ll tt){
ll ans = 0;
for(ll i = 0; i < cnt; i++){
if (a[i].pos <= pos) {
ans += a[i].w*C(pos-a[i].pos+tt-a[i].tt-1, tt-a[i].tt-1)%mod;
ans %= mod;
}
}
return ans;
}
int main () {
ll t;
ll pt, l, r, w;
init();
cin >> t;
while(t--){
cin >> n >> m;
cnt = 0; ll tt = 1;
while(m--){
scanf("%lld", &pt);
if (pt == 1){
scanf("%lld%lld%lld", &l, &r, &w);
a[cnt].tt = tt-1, a[cnt].pos = l, a[cnt].w = w%mod; cnt++;
a[cnt].tt = tt-1, a[cnt].pos = r+1, a[cnt].w = -w%mod; cnt++;
}
else if (pt == 2) tt++;
else {
scanf("%lld%lld", &l, &r);
printf("%lld\n", ((query(r, tt+1)-query(l-1, tt+1))%mod+mod)%mod);
}
}
}
return 0;
}