BZOJ4832抵制克蘇恩
阿新 • • 發佈:2019-01-05
我們是在從後往前推 ,即我們是在用當前局推上一局
i:表示還有i次沒打,a:表示上一局血量為1的還有多少個,b:2,c:3
f[i]中a,b,c考慮這一局和上一局比a,b,c的變化
double k=1/(1+a+b+c) //我們要轉移狀態選擇每一個人物的概率(因為有一個英雄,所以+1) int tot=a+b+c; f[i+1][a][b][c]+=(f[i][a][b][c]+1)*k;//攻擊英雄 if(a) f[i+1][a][b][c]+=f[i][a-1][b][c]*a*k;//攻擊血量為1的隨從,死亡 if(b) { if(tot<7) f[i+1][a][b][c]+=f[i][a+1][b-1][c+1]*b*k;//可以增加奴隸主 else f[i+1][a][b][c]+=f[i][a+1][b-1][c]*b*k; } if(c) { if(tot<7) f[i+1][a][b][c]+=f[i][a][b+1][c]*c*k; else f[i+1][a][b][c]+=f[i][a][b+1][c-1]*c*k; }
這就是期望dp的核心
嗯,也沒什麼好說的了,程式碼:
#include<cstdio> #include<iostream> using namespace std; double f[60][10][10][10]; int t; int read() { int num=0,f=1; char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getchar();} while(isdigit(ch)) num=(num<<3)+(num<<1)+(ch^48),ch=getchar(); return num*f; } void work() { for(int i=0;i<50;i++) for(int a=0;a<=7;a++) for(int b=0;b<=7-a;b++) for(int c=0;c<=7-a-b;c++) { double k=1.0/(1+a+b+c); int tot=a+b+c; f[i+1][a][b][c]+=(f[i][a][b][c]+1)*k; if(a) f[i+1][a][b][c]+=f[i][a-1][b][c]*a*k; if(b) { if(tot<7) f[i+1][a][b][c]+=f[i][a+1][b-1][c+1]*b*k; else f[i+1][a][b][c]+=f[i][a+1][b-1][c]*b*k; } if(c) { if(tot<7) f[i+1][a][b][c]+=f[i][a][b+1][c]*c*k; else f[i+1][a][b][c]+=f[i][a][b+1][c-1]*c*k; } } } int main() { work(); t=read(); while(t--) { int k=read(),a=read(),b=read(),c=read(); printf("%.2lf\n",f[k][a][b][c]); } return 0; }