1. 程式人生 > >BZOJ4832抵制克蘇恩

BZOJ4832抵制克蘇恩

我們是在從後往前推 ,即我們是在用當前局推上一局

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;
}