校內模擬賽 Zbq's Music Challenge
Zbq‘s Music Challenge
題意:
一個長度為n的序列,每個位置可能是1或者0,1的概率是$p_i$。對於一個序列$S$,它的得分是
$$BasicScore=A\times \sum_{i=1}^{n}{S_i} \tag{1}$$
$$ combo(i)=\left\{ \begin{aligned} &S_i & &i=1 \\ &combo(i-1)+1 & &i\neq 1 ~\mathrm{and}~ S_i=1 \\ &combo(i-1)\times t & &\mathrm{otherwise} \end{aligned} \tag{2} \right.$$
$$ComboScore=B\times \sum_{i=1}^{n}{S_i\times combo(i)} \tag{3}$$
$$TotalScore=BasicScore+ComboScore \tag{4}$$
兩種操作,修改每個位置的概率,詢問一段區間得分的期望,答案對$998244353$取模。
分析:
分成兩部分算,$BasicScore$可以對$p_i$求和得到。
對於每段區間,$f[i]$設第i位置數字期望是多少,那麽$ComboScore = B \times \sum\limits_{i=l}^{r} p_i \times (f[i-1] + 1) $。
然後轉移可以寫成矩陣的形式。
$$ \left[ \begin{matrix} 0 & p_i & p_i \\ 0 & (1 - p_i) \times t + p_i & p_i\\ 0 & 0 & 1 \end{matrix} \right] \times \left[ \begin{matrix} sum\\ f[i - 1]\\ 1 \end{matrix} \right] = \left[ \begin{matrix} sum‘ \\ f[i]\\ 1 \end{matrix} \right] $$
於是,線段樹維護一下即可。復雜度$O(nlogn \times 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 << "\n"; } 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; }
校內模擬賽 Zbq's Music Challenge