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

猜你喜欢

转载自www.cnblogs.com/cmwqf/p/10223774.html