F 到底是多少分啊
设最终第 项的值为 ,也就是说第 项的值加了 ,那么由题意可知 。
最终的期望 ,其中 为 不同解的个数。
令 ,那么枚举第 项加了几个 ,可以得到 。
这个转移方程的复杂度是
这显然可以NTT
将转移方程拆开,发现我们只需要快速计算 即可,因为用前缀和容易维护 。
观察 和式的变化。
显然下面的那个式子比上面那个式子多了 。
于是也能用前缀和维护。
这样期望的分子部分已经计算完毕了,至于分母的那个 ,是一个经典的整数拆分问题,就不过多赘述了,有很多的方法能去做,代码里面用的依然是 的思想。
时间复杂度:
代码:
#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;
}