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;
}
posted @ 2019-01-05 11:27  cmwqf  阅读(121)  评论(0)    收藏  举报