Solution
给我的感觉就是很暴力的计数DP。
因为再暴力,这也算个DP
那么我们可以显然的构造出一个状态 (f_{i,a,b,c,1/0}) ,表示现在是第 (i) 个踏板放在某个面上,其它三个面的下一个踏板距离这个的距离为 (a,b,c) ,当前这个踏板是/否能从地面到达。
在此我们是优化了一维,也就是将 (i) 踏板所在面下一个距离这个踏板的距离优化成了 (1/0) ,因为能到达的时候距离是 (<h) 的,不能时是 (geq h) 的,也是两个状态。
再思考另一个问题,开了五维数组,那么空间复杂度是 (O(n imes n imes n imes n imes 2)=O(n^4)) ,显然是会炸的。我们还得优化空间,发现题目中说明 (hleq min(n,30)) ,所以可以将 (a,b,c) 三维的空间变成30,当距离 (geq h) 时,赋为 (h) 。此时为 (O(2cdot 30^3cdot n)) ,完全可以。
再看时间复杂度。发现我们在优化空间的时候,把时间复杂度也降低了。本来要枚举五维,复杂度是 (O(n^5)) ,现在也变成了 (O(2cdot 30^3cdot 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
",ans);
}