F 到底是多少分啊

设最终第 ii 项的值为 ai+xia_i+x_i,也就是说第 ii 项的值加了 xix_i,那么由题意可知 xi=t\sum x_i = t

最终的期望 E=x1+x2++xn=ti=1n(ai+xi)numE=\frac{\sum\limits_{x_1+x_2+\cdots+x_n=t}\prod\limits_{i=1}^n(a_i+x_i)}{num},其中 numnumx1+x2++xn=tx_1+x_2+\cdots+x_n=t 不同解的个数。

dpi,j=x1+x2++xi=jk=1i(ak+xk)dp_{i,j}=\sum\limits_{x_1+x_2+\cdots+x_i=j}\prod\limits_{k=1}^i(a_k+x_k),那么枚举第 ii 项加了几个 11,可以得到 dpi,j=k=0jdpi1,jk×(ai+k)dp_{i,j}=\sum\limits_{k=0}^jdp_{i-1,j-k}\times(a_i+k)

这个转移方程的复杂度是 O(nt2)O(nt^2) 的,考虑优化。

这显然可以NTT

将转移方程拆开,发现我们只需要快速计算 k×dpi1,jk\sum k\times dp_{i-1,j-k} 即可,因为用前缀和容易维护 ai×dpi1,jk\sum a_i\times dp_{i-1,j-k}

观察 jj+1j \rightarrow j+1 和式的变化。

j:0×dpi1,j+1×dpi1,j1+2×dpi1,j2++j×dpi1,0j:0\times dp_{i-1,j}+1\times dp_{i-1,j-1}+2\times dp_{i-1,j-2}+\cdots+j\times dp_{i-1,0}

j+1:0×dpi1,j+1+1×dpi1,j+2×dpi1,j1++(j+1)×dpi1,0j+1:0\times dp_{i-1,j+1}+1\times dp_{i-1,j}+2\times dp_{i-1,j-1}+\cdots+(j+1)\times dp_{i-1,0}

显然下面的那个式子比上面那个式子多了 dpi1,j+dpi1,j1++dpi1,0dp_{i-1,j}+dp_{i-1,j-1}+\cdots+dp_{i-1,0}

于是也能用前缀和维护。

这样期望的分子部分已经计算完毕了,至于分母的那个 numnum,是一个经典的整数拆分问题,就不过多赘述了,有很多的方法能去做,代码里面用的依然是 dpdp 的思想。

时间复杂度:O(nt)O(nt)

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 998244353;
const int maxn = 1e5 + 10;
#define __cs() int T; cin >> T; while (T--)
#define endl '\n'
ll qpow(ll a, int b, ll ans = 1) { for (; b; (a *= a) %= mod, b >>= 1)if (b & 1)(ans *= a) %= mod; return ans; }
ll n, t, a[3005], dp[3005][3005], num[3005][3005];
void solve() {
    scanf("%lld%lld", &n, &t);
    for (int i = 1; i <= n; ++i) {
        scanf("%lld", &a[i]);
    }
    dp[0][0] = num[0][0] = 1;
    for (int i = 1; i <= n; ++i) {
        ll sum = 0, pre = 0, all = 0;
        for (int j = 0; j <= t; ++j) {
            (pre += dp[i - 1][j]) %= mod;
            (all += num[i - 1][j]) %= mod;
            dp[i][j] = (a[i] * pre + sum) % mod;
            num[i][j] = all;
            (sum += pre) %= mod;
        }
    }
    printf("%lld\n", dp[n][t] * qpow(num[n][t], mod - 2) % mod);
}
int main() {
    solve();
    return 0;
}