XSY Dissertation6-贪心和DP专题——概率与期望dp 【BZOJ4318】【BZOJ3566】【BZOJ3029】
【BZOJ4318】OSU!
题意简述
osu 是一款群众喜闻乐见的休闲软件。
我们可以把osu的规则简化与改编成以下的样子:
一共有n次操作,每次操作只有成功与失败之分,成功对应1,失败对应0,n次操作对应为1个长度为n的01串。在这个串中连续的 X个1可以贡献X^3 的分数,这x个1不能被其他连续的1所包含(也就是极长的一串1,具体见样例解释)
现在给出n,以及每个操作的成功率,请你输出期望分数,输出四舍五入后保留1位小数。、
Input
第一行有一个正整数n,表示操作个数。接下去n行每行有一个[0,1]之间的实数,表示每个操作的成功率。
Output
只有一个实数,表示答案。答案四舍五入后保留1位小数。
Sample Input
3
0.5
0.5
0.5
Sample Output
6.0
HINT 样例说明
000分数为0,001分数为1,010分数为1,100分数为1,101分数为2,110分数为8,011分数为8,111分数为27,总和为48,期望为48/8=6.0
N<=100000
Latex什么的没有,能看就行,重在题解嘛对吧
题解
对于我们在处理当前的一个位置i,假设i-1的期望为\(a\),那么如果当前操作成功,能够加上
这样子就把一个整体的东西拆成了一个一个加和。
注意的是期望的平方不等于平方的期望,要分开。
#include<cstdio>
using namespace std;
const int N=100010;
int n;
double x1[N], x2[N], f[N];
int main() {
scanf("%d", &n);
for(int i=1; i<=n; i++) {
double ng;
scanf("%lf", &ng);
f[i]=f[i-1]+ng*(3*x2[i-1]+3*x1[i-1]+1);
x1[i]=(x1[i-1]+1)*ng;
x2[i]=(x2[i-1]+2*x1[i-1]+1)*ng;
}
printf("%.1lf", f[n]);
}
【BZOJ3566】【SHOI2014】概率充电器
经典老题了啊。题面就不给了。
我还傻乎乎的以为通电的期望可以直接加起来,然后发现一堆点的通电期望大于1。。。。
实际上由于通电的期望中有重叠,所以我们需要 容斥一下。但是由于对于一个点可能通电的情况一直在加,那么这样容斥就几乎不可能了。
所以我们为什么不考虑不通电的期望呢,不通电是且的关系,也就是上面的电不来电且这个点不通电且下面的点不来电,这样就可以乘起来了,不像通电,是或的关系。
既然乘起来那当然就好搞了。
注意两个式子。我们这里h[i]输入时表示一个点不通电的概率。
在\(dfs1\)中我们处理他和他的儿子没有电通过来的期望。
在\(dfs2\)中我们处理一个点不从上面来电的期望,也就是说对于一个点不向他儿子导电的期望,用数组\(h1\)表示。
也就是最后父亲点既不从祖父点,也不从自己和儿子来电的期望,除了当前在处理的儿子点我们爱管不管,因为对于儿子点我们只考虑父亲不来电,儿子向不向父亲来电不在我们讨论范围。
也很好理解。
#include<cstdio>
using namespace std;
const int N=500010;
struct EDGE {
int y, nex;
double c;
}edge[N<<1];
int n, head[N], cnt;
double h[N], h1[N];
void add(int x, int y, double c) {
edge[++cnt].y=y;
edge[cnt].c=c;
edge[cnt].nex=head[x];
head[x]=cnt;
}
void dfs1(int x, int fa) {
for(int i=head[x]; i; i=edge[i].nex) {
int y=edge[i].y;
if(y==fa) continue;
dfs1(y, x);
h[x]*=(h[y]+(1-h[y])*edge[i].c);
}
}
void dfs2(int x, int fa) {
if(!fa) h1[x]=1;
for(int i=head[x]; i; i=edge[i].nex) {
int y=edge[i].y;
if(y==fa) continue;
double P=h[x]*h1[x]/(h[y]+(1-h[y])*edge[i].c);
h1[y]=P+(1-P)*edge[i].c;
dfs2(y, x);
}
}
int main() {
scanf("%d", &n);
for(int i=1; i<n; i++) {
int x, y; double c;
scanf("%d%d%lf", &x, &y, &c);
c=100-c;
c/=100;
add(x, y, c), add(y, x, c);
}
for(int i=1; i<=n; i++) scanf("%lf", &h[i]), h[i]=(100-h[i])/100;
dfs1(1, 0);
dfs2(1, 0);
double ans=0;
for(int i=1; i<=n; i++) ans+=1ll-h[i]*h1[i];
printf("%.6lf", ans);
}
【CF167B】【BZOJ3029】守卫者的挑战
题意简述
打开了黑魔法师Van的大门,队员们在迷宫般的路上漫无目的地搜寻着关押平家boy的监狱的所在地。突然,眼前一道亮光闪过。“我,Billy,是黑魔法圣殿的守卫者。如果你能通过我的挑战,那么你可以带走黑魔法圣殿的地图……”瞬间,队员们被传送到了一个擂台上,最初身边有一个容量为K的包包。
擂台赛一共有N项挑战,各项挑战依次进行。第i项挑战有一个属性ai,如果ai>=0,表示这次挑战成功后可以再获得一个容量为ai的包包;如果ai=-1,则表示这次挑战成功后可以得到一个大小为1 的地图残片。地图残片必须装在包包里才能带出擂台,包包没有必要全部装满,但是队员们必须把 【获得的所有的】地图残片都带走(没有得到的不用考虑,只需要完成所有N项挑战后背包容量足够容纳地图残片即可),才能拼出完整的地图。并且他们至少要挑战成功L次才能离开擂台。
队员们一筹莫展之时,光明的守卫者Billy帮忙预估出了每项挑战成功的概率,其中第i项挑战成功的概率为pi%。现在,请你帮忙预测一下,队员们能够带上他们获得的地图残片离开擂台的概率。
输入
第一行三个整数N,L,K。
第二行N个实数,第i个实数pi表示第i项挑战成功的百分比。
第三行N个整数,第i个整数ai表示第i项挑战的属性值.
输出
一个整数,表示所求概率,四舍五入保留6 位小数。
样例
3 1 0
10 20 30
-1 -1 2
0.300000
HINT
若第三项挑战成功,如果前两场中某场胜利,队员们就有空间来容纳得到的地图残片,如果挑战失败,根本就没有获得地图残片,不用考虑是否能装下;若第三项挑战失败,如果前两场有胜利,没有包来装地图残片,如果前两场都失败,不满足至少挑战成功次()的要求。因此所求概率就是第三场挑战获胜的概率。
对于 100% 的数据,保证0<=K<=2000,0<=N<=200,-1<=ai<=1000,0<=L<=N,0<=pi<=100。
这数据范围不是肯定的暴力吗
直接上\(O(n^3)\)
\(f_{ijk}\)表示打到\(i\)局赢了\(j\)局获得容量为\(k\)的背包。
显然如果\(当前状态中k>n\)那就一定装得下, 那就干脆超过的全部用\(N\)代替吧。
\(XSY\)贼不要脸改了数据范围把\(k\)从\(200\)改到\(2000\),还改了空间逼我用滚动数组。
#include<bits/stdc++.h>
using namespace std;
const int N=200;
int n, m, k;
double f[2][N+10][(N<<1)+10], ans;
int a[N+10], b[N+10];
int main() {
scanf("%d%d%d", &n, &m, &k);
for(int i=1; i<=n; i++) scanf("%d", &a[i]);
for(int i=1; i<=n; i++) scanf("%d", &b[i]);
if(k+N>2*N) f[0][0][2*N]=1;
else f[0][0][k+N]=1;
int ii=1;
for(int i=1; i<=n; i++, ii^=1) {
memset(f[ii], 0, sizeof(f[ii]));
for(int j=0; j<i; j++) {
for(int k=0; k<=2*N; k++) {
if(b[i]==-1) {
if(k>0)
f[ii][j+1][k-1]+=f[ii^1][j][k]*0.01*a[i];
} else {
if(k+b[i]>2*N)
f[ii][j+1][2*N]+=f[ii^1][j][k]*0.01*a[i];
else
f[ii][j+1][k+b[i]]+=f[ii^1][j][k]*0.01*a[i];
}
f[ii][j][k]+=f[ii^1][j][k]*(1-0.01*a[i]);
}
}
}
ii^=1;
for(int i=m; i<=n; i++) {
for(int j=N; j<=N<<1; j++) {
ans+=f[ii][i][j];
}
}
printf("%.6f", ans);
}

浙公网安备 33010602011771号