Codeforces 596D 区间DP

原创 2015年11月19日 00:12:35

题目链接:

题意:

  有n棵树排成一排,高度都为h.

  主人公要去砍树,每次等概率地随机选择没倒的树中最左边的树或者最右边的树把它砍倒.每棵树被砍到后,有p的概率会往左边倒,(1-p)的概率往右边倒.

  树倒下后如果压到别的树,即如果那棵树倒下的方向上距离不到h的地方还有一棵树,,那么那棵树也会朝和这个树相同的方向倒下.

  问最后所有的树都被砍完后覆盖的地面的长度的期望.



分析:

  由于树的数量n只有1000,所以O(n^2)的方法是可行的.很自然就能想到区间DP.

  设DP(l,r,s1,s2)为砍掉第l棵树到第r棵树之间的所有树,并且第l-1棵树的状态s1,第r+1棵树的状态是s2,此时覆盖地面的长度的期望.其中,s1和s2只有0和1两种取值,0表示向左倒,1表示向右倒.

  那么最后的结果即DP(1,n,0,1),第0棵树和第n+1棵树要设的足够远以免对结果产生影响.

  状态的转移慢慢推就好.

  DP(l,r,s1,s2)的结果可以从DP(l+1,r,0,s2),DP(l+1,r,1,s2),DP(l,r-1,s1,0),DP(l,r-1,s1,1)四种情况推导出来.

  需要注意的是边界条件.

  具体还是看代码吧.


#include <bits/stdc++.h>
using namespace std;
const int maxn=2005;
int h;
double p;
int a[maxn];
double dp[maxn][maxn][2][2];
double DW(int l,int r,int sl,int sr)
{
	if (dp[l][r][sl][sr]) return dp[l][r][sl][sr];
	if (l==r) 
	{
		if (sl&&a[l-1]+h>a[l]) 
		{
			if (sr) return dp[l][r][sl][sr]=min(h,a[l+1]-a[l]);
			else return dp[l][r][sl][sr]=min(h,max(0,a[r+1]-a[r]-h));
		}
		else if (!sr&&a[r+1]-h<a[r]) 
		{
			if (sl) return dp[l][r][sl][sr]=min(h,max(a[l]-a[l-1]-h,0));
			else return dp[l][r][sl][sr]=min(h,a[l]-a[l-1]);
		}
		double ans=0;
		if (sl) ans+=p*min(h,max(a[l]-a[l-1]-h,0));
		else ans+=p*min(h,a[l]-a[l-1]);
		if (sr) ans+=(1-p)*min(h,a[r+1]-a[r]);
		else ans+=(1-p)*min(h,max(0,a[r+1]-a[r]-h));
		return dp[l][r][sl][sr]=ans;
	}
	if (sl&&a[l-1]+h>a[l])       return dp[l][r][sl][sr]=DW(l+1,r,1,sr)+min(h,a[l+1]-a[l]);
	else if (!sr&&a[r+1]-h<a[r]) return dp[l][r][sl][sr]=DW(l,r-1,sl,0)+min(h,a[r]-a[r-1]);
	double ans=0;
	ans+=0.5*(1-p)*(DW(l+1,r,1,sr)+min(h,a[l+1]-a[l]));
	ans+=0.5*p    *(DW(l,r-1,sl,0)+min(h,a[r]-a[r-1]));
	if (sl) ans+=0.5*p*(DW(l+1,r,0,sr)+min(h,max(0,a[l]-a[l-1]-h)));
	else    ans+=0.5*p*(DW(l+1,r,0,sr)+min(h,a[l]-a[l-1]));
	if (sr) ans+=0.5*(1-p)*(DW(l,r-1,sl,1)+min(h,a[r+1]-a[r]));
	else    ans+=0.5*(1-p)*(DW(l,r-1,sl,1)+min(h,max(0,a[r+1]-a[r]-h)));
	return dp[l][r][sl][sr]=ans;
}
int main()
{
	int n;
	while (~scanf("%d%d%lf",&n,&h,&p))
	{
		for (int i=1;i<=n;i++) scanf("%d",&a[i]);
		memset(dp,0,sizeof(dp));
		sort(a+1,a+n+1);
		a[0]=a[1]-h;
		a[n+1]=a[n]+h;
		printf("%.12lf\n",DW(1,n,0,1));
	}
	return 0;
}



版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

Codeforces Round #106(Div. 2) 149D. Coloring Brackets 区间DP 记忆化搜索

D. Coloring Brackets time limit per test 2 seconds memory limit per test 256 megabytes ...

CodeForces - 149D Coloring Brackets(区间dp)

题目链接这是一道区间dp的题目……怎么说呢,让我认识到我之前对区间dp的理解太浅显和模式化了,总觉得就是枚举每个区间段就可以了, ==确实是我刷的题还太少。 这道题目也是对于这些颜色该怎么处理无从下...
  • ciel_s
  • ciel_s
  • 2017年03月10日 18:15
  • 83

CodeForces 149D Coloring Brackets(区间DP)

题目链接:Coloring Brackets #define mem(a,x) memset(a,x,sizeof(a)) #include #include #include #include #i...

Codeforces-149D-Coloring Brackets【区间DP】

给一个给定括号序列,给该括号上色。 上色规则: 1.只能选择红色、蓝色、无色 2.每对括号,只能给其中一个上色 3.相邻两个颜色不可相同,但可以都为无色...

codeforces 331D 河狸boshi 【区间dp+期望】

区间dp+期望
  • litble
  • litble
  • 2017年07月04日 18:54
  • 186

Codeforces149D(计数区间dp)

题意: 给出串规律的括号(括号是匹配好的)比如说 ( ( ) ( ) )   这个括号的真确匹配是 第一个和最后一个、第二个和第三个、第四个和第五个。 现在要给括号染色,给出这些条件: 1、括号可以不...

CodeForces-149D Coloring Brackets(区间dp)

D - Coloring Brackets  CodeForces - 149D  题意:给一个合法的括号串,然后问这串括号有多少种涂色方案,涂色要求为: ①每个括号只有三种...

codeforces 149D Coloring Brackets 区间DP

题意:给你一串括号,每个括号可以涂色,蓝色或者红色或者不涂,问你有多少种方案数,其中涂色有些限制。 1.每对括号有且仅有其中一个被涂色。 2.相邻的括号不能涂相同的颜色,但是相邻的括号可以同时不涂...

Codeforces 149D Coloring Brackets (不错的区间DP)

题意给出一个合法的括号序列,要求给这个序列染色,求染色方案。 1.可以选择无色、红色、蓝色。 2.每一对括号要有且仅有一个染色的括号。 3.相邻的括号不能有相同的颜色(无色没关系)思路显然是个区...

CodeForces - 149D Coloring Brackets[区间dp]

原题链接       cf 149D Coloring Brackets voj题目链接  cf 149D Coloring Brackets    题目要求是 给一个完整的括号匹配序列...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Codeforces 596D 区间DP
举报原因:
原因补充:

(最多只允许输入30个字)