【省内训练2018-12-21】Chocolate

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39972971/article/details/85212180

【思路要点】

  • 首先,定义 tt 次成功率为 pp 的操作恰好成功 xx 次的概率为 ft,p(x)f_{t,p}(x) ,有 ft,p(x)=px(1p)tx(tx)f_{t,p}(x)=p^x(1-p)^{t-x}\binom{t}{x}
  • 对于任意一行,留下的部分是区间 [l,r][l,r] 的概率为 ft,p(l1)ft,p(Mr)f_{t,p}(l-1)*f_{t,p}(M-r)
  • 考虑一个直观的 O(NM2)O(NM^2) 的动态规划做法,记 dpi,j,kdp_{i,j,k} 表示前 ii 行连通,并且第 ii 行留下的区间为 [j,k][j,k] 的概率,记 prei,x=j=1xk=jxdpi,j,k,sufi,x=j=xMk=jMdpi,j,kpre_{i,x}=\sum_{j=1}^{x}\sum_{k=j}^{x}dp_{i,j,k},suf_{i,x}=\sum_{j=x}^{M}\sum_{k=j}^{M}dp_{i,j,k} ,显然有转移 dpi,j,k=ft,p(j1)ft,p(Mk)(prei1,Mprei1,j1sufi1,k+1)dp_{i,j,k}=f_{t,p}(j-1)*f_{t,p}(M-k)*(pre_{i-1,M}-pre_{i-1,j-1}-suf_{i-1,k+1})
  • 我们发现转移时并不需要知道 dpi,j,kdp_{i,j,k} ,只需要知道 prei,xpre_{i,x}sufi,xsuf_{i,x} 即可。
  • 考虑直接利用 prei,xpre_{i,x}sufi,xsuf_{i,x} 进行动态规划,以计算 prei,xpre_{i,x} 为例,记 prei,x=j=1xdpi,j,xpre'_{i,x}=\sum_{j=1}^{x}dp_{i,j,x} ,显然 prei,xpre_{i,x} 就是 prei,xpre'_{i,x} 的前缀和。那么根据上面的计算式,有 prei,k=j=1kft,p(j1)ft,p(Mk)(prei1,Mprei1,j1sufi1,k+1)pre'_{i,k}=\sum_{j=1}^{k}f_{t,p}(j-1)*f_{t,p}(M-k)*(pre_{i-1,M}-pre_{i-1,j-1}-suf_{i-1,k+1}) ,可以发现,若将括号拆开,每一项都可以表示为只和 i,ki,k 相关的一个量乘以只和 i,ji,j 相关的一个量,可以通过部分和进行优化。
  • 时间复杂度为 O(NM+T)O(NM+T)

【代码】

#include<bits/stdc++.h>
using namespace std;
const int MAXM = 2e5 + 5;
const int MAXN = 3005;
const int P = 1e9 + 7;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
int pre[2][MAXN], suf[2][MAXN];
int n, m, p, q, t, lp[MAXN], rp[MAXN];
int fac[MAXM], inv[MAXM], powp[MAXM], powq[MAXM];
void update(int &x, int y) {
	x = (x + y >= P) ? (x + y - P) : (x + y);
}
void getdp() {
	static int sumlp[MAXN], sumrp[MAXN];
	for (int i = 1; i <= m; i++) {
		sumlp[i] = (sumlp[i - 1] + lp[i]) % P;
		pre[1][i] = 1ll * sumlp[i] * rp[i] % P;
		update(pre[1][i], pre[1][i - 1]);
	}
	for (int i = m; i >= 1; i--) {
		sumrp[i] = (sumrp[i + 1] + rp[i]) % P;
		suf[1][i] = 1ll * sumrp[i] * lp[i] % P;
		update(suf[1][i], suf[1][i + 1]);
	}
	for (int i = 2, now = 0, from = 1; i <= n; i++, swap(now, from)) {
		int tmp = 0;
		for (int j = 1; j <= m; j++) {
			pre[now][j] = 1ll * sumlp[j] * pre[from][m] % P;
			update(tmp, 1ll * pre[from][j - 1] * lp[j] % P);
			update(pre[now][j], P - tmp);
			update(pre[now][j], P - 1ll * sumlp[j] * suf[from][j + 1] % P);
			pre[now][j] = 1ll * pre[now][j] * rp[j] % P;
			update(pre[now][j], pre[now][j - 1]);
		}
		tmp = 0;
		for (int j = m; j >= 1; j--) {
			suf[now][j] = 1ll * sumrp[j] * pre[from][m] % P;
			update(tmp, 1ll * suf[from][j + 1] * rp[j] % P);
			update(suf[now][j], P - tmp);
			update(suf[now][j], P - 1ll * sumrp[j] * pre[from][j - 1] % P);
			suf[now][j] = 1ll * suf[now][j] * lp[j] % P;
			update(suf[now][j], suf[now][j + 1]);
		}
	}
}
int power(int x, int y) {
	if (y == 0) return 1;
	int tmp = power(x, y / 2);
	if (y % 2 == 0) return 1ll * tmp * tmp % P;
	else return 1ll * tmp * tmp % P * x % P;
}
int getc(int x, int y) {
	if (y > x) return 0;
	else return 1ll * fac[x] * inv[y] % P * inv[x - y] % P;
}
int getp(int x) {
	return 1ll * getc(t, x) * powp[x] % P * powq[t - x] % P;
}
void init(int n) {
	fac[0] = powp[0] = powq[0] = 1;
	for (int i = 1; i <= n; i++) {
		fac[i] = 1ll * fac[i - 1] * i % P;
		powp[i] = 1ll * powp[i - 1] * p % P;
		powq[i] = 1ll * powq[i - 1] * q % P;
	}
	inv[n] = power(fac[n], P - 2);
	for (int i = n - 1; i >= 0; i--)
		inv[i] = inv[i + 1] * (i + 1ll) % P;
	for (int i = 1; i <= m; i++) {
		lp[i] = getp(i - 1);
		rp[i] = getp(m - i);
	}
}
int main() {
	freopen("chocolate.in", "r", stdin);
	freopen("chocolate.out", "w", stdout);
	read(n), read(m);
	read(p), read(q);
	p = 1ll * p * power(q, P - 2) % P;
	q = (P + 1 - p) % P;
	read(t), init(t), getdp();
	printf("%d\n", pre[n & 1][m]);
	return 0;
}

没有更多推荐了,返回首页

私密
私密原因:
请选择设置私密原因
  • 广告
  • 抄袭
  • 版权
  • 政治
  • 色情
  • 无意义
  • 其他
其他原因:
120
出错啦
系统繁忙,请稍后再试