CF268D Wall Bars

Solution

给我的感觉就是很暴力的计数DP。

因为再暴力,这也算个DP

那么我们可以显然的构造出一个状态 \(f_{i,a,b,c,1/0}\) ,表示现在是第 \(i\) 个踏板放在某个面上,其它三个面的下一个踏板距离这个的距离为 \(a,b,c\) ,当前这个踏板是/否能从地面到达。

在此我们是优化了一维,也就是将 \(i\) 踏板所在面下一个距离这个踏板的距离优化成了 \(1/0\) ,因为能到达的时候距离是 \(<h\) 的,不能时是 \(\geq h\) 的,也是两个状态。

再思考另一个问题,开了五维数组,那么空间复杂度是 \(O(n\times n\times n\times n\times 2)=O(n^4)\) ,显然是会炸的。我们还得优化空间,发现题目中说明 \(h\leq \min(n,30)\) ,所以可以将 \(a,b,c\) 三维的空间变成30,当距离 \(\geq h\) 时,赋为 \(h\) 。此时为 \(O(2\cdot 30^3\cdot n)\) ,完全可以。

再看时间复杂度。发现我们在优化空间的时候,把时间复杂度也降低了。本来要枚举五维,复杂度是 \(O(n^5)\) ,现在也变成了 \(O(2\cdot 30^3\cdot n)\)

现在终于到了最重要的转移方程:

\[f_{i+1,a+1,b+1,c+1,1/0}+=f_{i,a,b,c,1/0} \]

这个是还在本来的那个面上

\[f_{i+1,1/h,b+1,c+1,[a<h]}+=f_{i,a,b,c,1/0} \]

这是换到另一个面

\[f_{i+1,a+1,1/h,c+1,[b<h]}+=f_{i,a,b,c,1/0}, f_{i+1,a+1,b+1,1/h,[c<h]}+=f_{i,a,b,c,1/0} \]

这两个同理。

答案随便求求即可。

代码

#include<bits/stdc++.h>
#define ll long long

using namespace std;
const int mod=1e9+9;
int n,h,ans;
int f[1010][31][31][31][2];

#define add(i,a,b,c,j,val) (f[i][min(a,h)][min(b,h)][min(c,h)][j]+=val)%=mod;
ll read(){
	int x=0,f=1;
	char ch=getchar();
	while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
	return x*f;
}

int main(){
	n=read();h=read();
	f[1][1][1][1][1]=4;
	for(int i=1;i<=n;i++)
		for(int a=1;a<=h;a++)
			for(int b=1;b<=h;b++)
				for(int c=1;c<=h;c++)
					for(int j=0;j<2;j++)
						if(f[i][a][b][c][j]){
							add(i+1,a+1,b+1,c+1,j,f[i][a][b][c][j]);
							int d=1;if(j==0) d=h;
							add(i+1,d,b+1,c+1,a<h,f[i][a][b][c][j]);
							add(i+1,a+1,d,c+1,b<h,f[i][a][b][c][j]);
							add(i+1,a+1,b+1,d,c<h,f[i][a][b][c][j]);
						}
	for(int a=1;a<=h;a++)
		for(int b=1;b<=h;b++)
			for(int c=1;c<=h;c++)
				for(int j=0;j<2;j++)
					if(j||a<h||b<h||c<h) ans=(ans+f[n][a][b][c][j])%mod;
	printf("%d\n",ans);
}
posted @ 2020-11-04 20:04  jasony_sam  阅读(92)  评论(0编辑  收藏  举报