牛客网暑期ACM多校训练营(第十场) Rikka with Prefix Sum

题目:https://www.nowcoder.com/acm/contest/148/D

题意:

给一个数组a,一开始的值全为0。一共有三个操作: 
1. 对区间[L,R]的每个数都加上w。 
2. 将数组a用其前缀和数组代替。 
3. 将询问区间[L,R]的区间和。

题解:大佬

/**
参考大佬题解:http://www.cnblogs.com/tetew/p/9504595.html
   0  1   2   3   4   5   6 (下标)
0  0  1   -1  0   0   0   0 (第0层)
1  0 (1)  0   0   0   0   0 (原数组 , 使a1 = 1)
2  0  1   1   1   1   1   1
3  0  1   2   3   4   5   6
4  0  1   3   6   10  15  21
5
.
.
--- x层是 x+1 层的差分。
---原来的序列的l-r区间+w,其实就是在它的差分序列l处+w,r+1处-w.
---所以如果在(i,j)点+w,那么(x,y)点的系数为C(x-i+y-j-1,x-i-1).
---求第x层的 sum(l,r) 相当于求 第 x+1 层的 a[r] - a[l-1].

**/
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long int ll;
const ll Mod = 998244353;
const int maxn = 2e5;
int n,m;
int qx[maxn+5],qy[maxn+5];
ll qw[maxn+5];
int nowx,q_cnt;

//---------C(a,b)代码。
ll fac[maxn+5],inv[maxn+5];
const ll MOD = Mod;
ll powi(ll a, ll b)
{
    ll c = 1;
    for (; b; b >>= 1, a = 1ll * a * a % MOD)
        if (b & 1) c = 1ll * c * a % MOD;
    return c;
}
void initC()
{
    int mx = maxn;
    fac[0] = 1; for (int i = 1; i <= mx; ++ i) fac[i] = 1ll * fac[i - 1] * i % MOD;
    inv[mx] = powi(fac[mx], MOD - 2); for (int i = mx - 1; ~i; -- i) inv[i] = 1ll * inv[i + 1] * (i + 1) % MOD;
}
ll C(int a, int b)
{
    return 1ll * fac[a] * inv[b] % MOD * inv[a - b] % MOD;
}
//-----------------

ll solve(int x,int y)
{
    ll sum = 0;
    for(int i=1;i<=q_cnt;i++)
    {
        if(qx[i]<=x&&qy[i]<=y)
        {
            sum = (sum + C( x-qx[i]+y-qy[i]-1, x-qx[i]-1 )*qw[i]%Mod + Mod)%Mod;
        }
    }
    return sum;
}
int main()
{
    int T;
    initC();
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d %d",&n,&m);
        nowx = 1, q_cnt = 0;
        for(int i=1;i<=m;i++)
        {
            int opt,l,r,w;
            scanf("%d",&opt);
            if(opt==1)
            {
                scanf("%d %d %d",&l,&r,&w);
                qx[++q_cnt] = nowx-1, qy[q_cnt] = l, qw[q_cnt] = 1ll*w%Mod;
                qx[++q_cnt] = nowx-1, qy[q_cnt] = r+1, qw[q_cnt] = 1ll*(Mod-w)%Mod;
            }
            if(opt==2) nowx++;
            if(opt==3)
            {
                scanf("%d %d",&l,&r);
                printf("%lld\n",( (solve(nowx+1,r) - solve(nowx+1,l-1))%Mod + Mod)%Mod);
            }
        }
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值