牛客多校10 D Rikka with Prefix Sum 不是数据结构

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

题意:

1e5个数,1e5个操作,操作分为:

1、区间加。

2、整个数列替换为前缀和。

3、区间查询。 查询数小于500.

题解:比赛时的思路是:(基本正确,没能实现)

1.对于某个操作1,记录下其之后操作2的个数,就可以通过组合数O(1)算出该区间的每个数最终的结果。

2.各个操作1相互独立,分开来算,最后相加。(暴力出来的规律)

没想到的两点:

1.可以通过组合数O(1)算出区间和:用公式

之前碰到过,杨辉三角上很明显。但直接导致我认为这个想法还是O(n*n/2)orz。

2.考虑某次区间加之后,操作2对该区间后面的数的影响:可以认为l~n加了v,r+1到n加了-v 正好抵消

另外:尝试了快速mod模板

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<map>
#include<string>
#include<bitset>

#define re register
#define rep(i,s,t) for(re int i=s;i<=t;++i)
#define per(i,s,t) for(re int i=s;i>=t;--i)
#define mmm(f,x) memset(f,x,sizeof f)
//#define x first
//#define xx second
using namespace std;

typedef  long long ll;

const ll mod = 998244353;
template<typename T>inline void add_(T &A, int B, ll MOD = mod) { A += B; (A >= MOD) && (A -= MOD); }
template<typename T>inline void mul_(T &A, ll B, ll MOD = mod) { A = (A*B) % MOD; }
template<typename T>inline void mod_(T &A, ll MOD = mod) { A %= MOD; A += MOD; A %= MOD; }
const int maxn = 3e5 + 5;
int a[maxn];
int n, m;
int tot,Q;
ll L[maxn], R[maxn],W[maxn],num2[maxn];
ll inv[maxn],  fac[maxn];
ll c[maxn];
long long kpow(long long a, long long n) {
    long long res = 1;
    while (n > 0) {
        if (n & 1)res = res * a%mod;
        a = a * a%mod;
        n >>= 1;
    }
    return res;
}
void init() {
    fac[0] = fac[1] = 1;
    inv[1] = 1;
    rep(i, 2, maxn) {
        fac[i] = fac[i - 1] * (ll)i % mod;
        inv[i] = kpow(fac[i], mod - 2);
    }
}
ll C(int n, int m) {
    if (n < m) return 0ll;
    if (m == 0 || n == m) return 1ll;
    if (n - 1 == m || m == 1) return n;
    return fac[n] * inv[m] % mod * inv[n - m] % mod;
}
ll Csum(ll l, ll r, ll v, ll q) {
    if (l>r)return 0;
    ll n = r - l + 1;
    ll ans = v;
    mul_(ans,C(q + n - 1, q));
    mod_(ans);
    return ans;
}
ll query(int x) {
    ll ret = 0;
    rep(i, 1, tot) {
        int q = Q - num2[i] + 1;
        if (L[i] > x)continue;
        if (R[i] <= x) {
            add_(ret, Csum(L[i], x, W[i], q));
            add_(ret, Csum(R[i] + 1, x, -W[i], q));
            mod_(ret);
        }
        else add_(ret, Csum(L[i], x, W[i], q));
    }
    return ret;
}
int main() {
    init();
    int t;
    cin >> t;
    while (t--) {
        tot = 0,Q=0;
        cin >> n >> m;
        rep(i, 1, m) {
            int op;
            scanf("%d", &op);
            if (op == 2) {
                Q++;
            }
            else {
                ll l, r;
                scanf("%lld%lld", &l, &r);
                
                if (op == 1) {
                    ll w; 
                    scanf("%lld", &w);
                    L[++tot] = l, R[tot] = r; W[tot] = w;
                    num2[tot] = Q;
                }
                else { cout<< (query(r) - query(l - 1) + mod) % mod << endl; }
            }
        }
    }
}
/*
1
100000 7
1 1 3 1
2
3 2333 6666
2
3 2333 6666
2
3 2333 6666
*/

 

posted @ 2018-08-19 21:31  SuuTTT  阅读(315)  评论(0编辑  收藏  举报