BZOJ4832 [Lydsy2017年4月月賽]抵制克蘇恩 記憶化搜尋
阿新 • • 發佈:2020-08-03
概率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; }