BZOJ4832 [Lydsy2017年4月月赛]抵制克苏恩 记忆化搜索
概率DP+记忆化搜索.
直接记忆化搜索感觉比较显然+简单.
直接设状态 $f[x][a][b][c]$ 表示还剩 $x$ 轮,当前牌的状态为 $(a,b,c)$ 还期望造成的伤害.
转移的话就是倒着转移:$f[x][a][b][c] \leftarrow f[x-1][.....]$.
然后边界的话将 $f[1][.....]$ 直接设为此时造成伤害的期望.
时间复杂度:$O(Tk8^3)$.
code:
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 54
#define ll long long
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
int vis[N][8][8][8];
double dp[N][8][8][8];
double solve(int x,int a,int b,int c) {
if(vis[x][a][b][c]) {
return dp[x][a][b][c];
}
double tmp=0.0;
tmp+=(solve(x-1,a,b,c)+1.0)/(a+b+c+1);
if(a) {
tmp+=solve(x-1,a-1,b,c)*1.0*a/(a+b+c+1);
}
if(b) {
if(a+b+c<7) tmp+=solve(x-1,a+1,b-1,c+1)*1.0*b/(a+b+c+1);
else {
tmp+=solve(x-1,a+1,b-1,c)*1.0*b/(a+b+c+1);
}
}
if(c) {
if(a+b+c<7) tmp+=solve(x-1,a,b+1,c)*1.0*c/(a+b+c+1);
else {
tmp+=solve(x-1,a,b+1,c-1)*1.0*c/(a+b+c+1);
}
}
vis[x][a][b][c]=1;
return dp[x][a][b][c]=tmp;
}
int main() {
//setIO("input");
for(int i=0;i<8;++i) {
for(int j=0;j<8;++j) {
for(int k=0;k<8;++k) {
if(i+j+k>7) continue;
dp[1][i][j][k]=1.0/(i+j+k+1);
vis[1][i][j][k]=1;
}
}
}
int T,k,A,B,C;
scanf("%d",&T);
while(T--) {
scanf("%d%d%d%d",&k,&A,&B,&C);
printf("%.2f\n",solve(k,A,B,C));
}
return 0;
}

浙公网安备 33010602011771号