https://www.luogu.com.cn/problem/P3600
每一步转换都不难,但许多步连在一起就不简单了
考虑怎么计算最大值为xxx的概率
这个也不好算,考虑算≤x\le x≤x的概率
也就是说对于每个区间,至少有一个数是≤x\le x≤x的概率
概率不好算,考虑算方案数
总的方案数显然是mnm^nmn,考虑dpdpdp
设f[i][j]f[i][j]f[i][j]表示已经填了前iii,填了jjj个≤x\le x≤x的,钦定第iii个是≤x\le x≤x的方案数
不难发现对于每个xxx,可以把≤x\le x≤x的数看成000,>x>x>x的数看成111,相当于是每个区间里至少有一个000
即转换后填了jjj个000合法的方案数为s[j]s[j]s[j]
显然s[j]=∑i[i之后全部填1都没关系]f[i][j]s[j]=\sum_i [i之后全部填1都没关系] f[i][j]s[j]=∑i?[i之后全部填1都没关系]f[i][j]
然后对于一个xxx,≤x\le x≤x方案数就是g[i]=∑js[j]×xj×(m?x)n?jg[i]=\sum_j s[j]\times x^j\times(m-x)^{n-j}g[i]=∑j?s[j]×xj×(m?x)n?j
p[i]=g[i]?g[i?1]mnp[i]=\frac{g[i]-g[i-1]}{m^n}p[i]=mng[i]?g[i?1]?
再用期望的定义式计算即可
code:
#include<bits/stdc++.h>
#define N 2005
#define ll long long
#define mod 666623333
using namespace std;
ll qpow(ll x, ll y) {
ll ret = 1;for(; y; y >>= 1, x = x * x % mod) if(y & 1) ret = ret * x % mod;return ret;
}
int n, m, q, R[N];
ll f[N][N], g[N], s[N];
int main() {
scanf("%d%d%d", &n, &m, &q);for(int i = 1; i <= n + 1; i ++) R[i] = n + 1;for(int i = 1; i <= q; i ++) {
int l, r;scanf("%d%d", &l, &r);R[l] = min(R[l], r);}for(int i = n - 1; i >= 1; i --) R[i] = min(R[i], R[i + 1]);f[0][0] = 1;for(int i = 1; i <= n; i ++) {
for(int j = 1; j <= i; j ++) {
for(int k = i - 1; k >= 0; k --) {
f[i][j] = (f[i][j] + f[k][j - 1]) % mod;if(R[k] < i) break;}}}// for(int i = 1; i <= n; i ++) {
// for(int j = 1; j <= n; j ++) printf(" %d ", f[i][j]); printf("\n");// }for(int i = 1; i <= n; i ++) for(int j = 0; j <= n; j ++) if(R[j + 1] == n + 1) s[i] = (s[i] + f[j][i]) % mod;// for(int i = 1; i <= n; i ++) printf("%lld ", R[i]); printf("\n"); // for(int i = 1; i <= n; i ++) printf("%lld ", s[i]); printf("\n");for(int i = 1; i <= m; i ++)for(int j = 1; j <= n; j ++) g[i] = (g[i] + qpow(i, j) * qpow(m - i, n - j) % mod * s[j] % mod) % mod;ll inv = qpow(qpow(m, n), mod - 2);for(int i = m; i >= 1; i --) g[i] = (g[i] - g[i - 1] + mod) % mod * inv % mod;ll ans = 0;for(int i = 1; i <= m; i ++) ans = (ans + g[i] * i % mod) % mod;printf("%lld", ans);return 0;
}