校内模拟赛 Zbq's Music Challenge

Zbq's Music Challenge

题意

  一个长度为n的序列,每个位置可能是1或者0,1的概率是$p_i$。对于一个序列$S$,它的得分是

$$BasicScore=A imes sum_{i=1}^{n}{S_i} ag{1}$$

$$ combo(i)=left{ egin{aligned} &S_i & &i=1 \ &combo(i-1)+1 & &i eq 1 ~mathrm{and}~ S_i=1 \ &combo(i-1) imes t & &mathrm{otherwise} end{aligned} ag{2} ight.$$

$$ComboScore=B imes sum_{i=1}^{n}{S_i imes combo(i)} ag{3}$$

$$TotalScore=BasicScore+ComboScore ag{4}$$

  两种操作,修改每个位置的概率,询问一段区间得分的期望,答案对$998244353$取模。

分析

  分成两部分算,$BasicScore$可以对$p_i$求和得到。

  对于每段区间,$f[i]$设第i位置数字期望是多少,那么$ComboScore = B imes sumlimits_{i=l}^{r} p_i imes (f[i-1] + 1) $。

  然后转移可以写成矩阵的形式。

  $$ left[ egin{matrix} 1 & p_i & p_i \ 0 & (1 - p_i) imes t + p_i & p_i\ 0 & 0 & 1 end{matrix} ight] imes left[ egin{matrix} sum\ f[i - 1]\ 1 end{matrix} ight] = left[ egin{matrix} sum' \ f[i]\ 1 end{matrix} ight] $$

  于是,线段树维护一下即可。复杂度$O(nlogn imes 3^3)$

代码

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cctype>
#include<cmath>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
using namespace std;
typedef long long LL;

inline int read() {
    int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
}

const int mod = 998244353;
const int N = 500005;
int p[N];

int ksm(int a,int b) {
    int res = 1;
    while (b) {
        if (b & 1) res = 1ll * res * a % mod;
        a = 1ll * a * a % mod;
        b >>= 1;
    }
    return res;
}
int fen(int a,int b) { return 1ll * a * ksm(b, mod - 2) % mod; }

int sum[N << 2], tt, NowAns, n, A, B;
struct Mat{ 
    int a[3][3]; 
    Mat() { memset(a, 0, sizeof(a)); }
    void set(int p) {
        a[0][0] = 1;
        a[0][1] = a[0][2] = a[1][2] = p;
        a[1][1] = (1ll * (mod + 1 - p) % mod * tt % mod + p) % mod;
        a[2][2] = 1;
    }
}T[N << 2];
Mat operator * (const Mat &A, const Mat &B) {
    Mat C;
    for (int k = 0; k < 3; ++k) 
        for (int i = 0; i < 3; ++i) 
            for (int j = 0; j < 3; ++j) 
                C.a[i][j] = (C.a[i][j] + 1ll * A.a[i][k] * B.a[k][j] % mod) % mod;
    return C;
}
inline void pushup(int rt) {
    T[rt] = T[rt << 1] * T[rt << 1 | 1]; 
    sum[rt] = (sum[rt << 1] + sum[rt << 1 | 1]) % mod;
}
void build(int l,int r,int rt) {
    if (l == r) {
        T[rt].set(p[l]); sum[rt] = p[l]; return ;        
    }
    int mid = (l + r) >> 1;
    build(l, mid, rt << 1); build(mid + 1, r, rt << 1 | 1);
    pushup(rt);
}
void update(int l,int r,int rt,int pos) {
    if (l == r) {
        T[rt].set(p[l]); sum[rt] = p[l]; return ;
    }
    int mid = (l + r) >> 1;
    if (pos <= mid) update(l, mid, rt << 1, pos);
    else update(mid + 1, r, rt << 1 | 1, pos);
    pushup(rt);
}
Mat query(int l,int r,int rt,int L,int R) {
    if (L <= l && r <= R) { NowAns = (NowAns + sum[rt]) % mod; return T[rt]; }
    int mid = (l + r) >> 1;
    if (R <= mid) return query(l, mid, rt << 1, L, R);
    else if (L > mid) return query(mid + 1, r, rt << 1 | 1, L, R);
    else return query(l, mid, rt << 1, L, R) * query(mid + 1, r, rt << 1 | 1, L, R);
}
void query() {
    int x = read(), y = read();
    NowAns = 0;
    Mat now = query(1, n, 1, x, y);
    LL ans1 = NowAns, ans2 = now.a[0][2];
    cout << (1ll * ans1 * A % mod + 1ll * ans2 * B % mod) % mod << "
";
}
int main() {
    read();
    n = read();int Q = read(), ta = read(), tb = read();A = read(), B = read();
    tt = fen(ta, tb);
    for (int i = 1; i <= n; ++i) 
        ta = read(), tb = read(), p[i] = fen(ta, tb);
    build(1, n, 1);
    while (Q --) {
        if (read()) query();
        else {
            int x = read(), ta = read(), tb = read(); 
            p[x] = fen(ta, tb);
            update(1, n, 1, x); 
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/mjtcn/p/10651188.html