[BZOJ 4008] 亚瑟王
Link:
Solution:
这题的约束:
(1)若一张牌发动了技能,那么将结束此回合。
(2)若一张牌发动过技能那么它不能再发动技能。
这意味着不能以回合数为状态来进行$dp$
由(2):一张牌最多发动一次技能,于是只要能算出每张牌的发动概率再统计即可
因此需要考虑经过卡牌的次数就好了,即给卡牌机会
设$dp[i][j]$表示给第$i$个元素分配$j$个机会的概率:
(1)若i-1没有用一个机会那么$dp[i][j]+=dp[i-1][j]*(1-dat[i-1])^j$
(2)若i-1用了一个机会那么$dp[i][j]+=dp[i-1][j+1]*(1-(1-dat[i-1])^j)$
(Note:这里并不用对每个卡牌只能发动一次进行特殊处理,简化为发动次数$>=1$的情况即可,毕竟结果只计算了一次)
Code:
//by NewErA #include <bits/stdc++.h> using namespace std; const int MAXN=500; int n,r,T; double d[MAXN],pw[MAXN][MAXN],dat[MAXN],dp[MAXN][MAXN]; int main() { scanf("%d",&T); while(T--) { scanf("%d%d",&n,&r);memset(dp,0,sizeof(dp)); for(int i=1;i<=n;i++) scanf("%lf%lf",&dat[i],&d[i]); for(int i=1;i<=n;i++) { pw[i][0]=1; for(int j=1;j<=r;j++) pw[i][j]=pw[i][j-1]*(1-dat[i]); } double res=0;dp[0][r]=1; for(int i=0;i<n;i++) for(int j=0;j<=r;j++) { dp[i+1][j]+=dp[i][j]*pw[i+1][j]; if(j>=1) { dp[i+1][j-1]+=dp[i][j]*(1-pw[i+1][j]); res+=dp[i][j]*(1-pw[i+1][j])*d[i+1]; } } printf("%.10lf\n",res); } return 0; }
Review:
从题目特点出发寻找状态的设定
如果各项独立,分开来计算