Description
Manao is working for a construction company. Recently, an order came to build wall bars in a children's park. Manao was commissioned to develop a plan of construction, which will enable the company to save the most money.
After reviewing the formal specifications for the wall bars, Manao discovered a number of controversial requirements and decided to treat them to the company's advantage. His resulting design can be described as follows:
- Let's introduce some unit of length. The construction center is a pole of height n.
- At heights 1, 2, ..., n exactly one horizontal bar sticks out from the pole. Each bar sticks in one of four pre-fixed directions.
- A child can move from one bar to another if the distance between them does not exceed h and they stick in the same direction. If a child is on the ground, he can climb onto any of the bars at height between 1 and h. In Manao's construction a child should be able to reach at least one of the bars at heights n - h + 1, n - h + 2, ..., n if he begins at the ground.
Manao is wondering how many distinct construction designs that satisfy his requirements exist. As this number can be rather large, print the remainder after dividing it by 1000000009 (109 + 9). Two designs are considered distinct if there is such height i, that the bars on the height i in these designs don't stick out in the same direction.
题意:
即在高度为N的杆子上,对于每一个高度x(1..N),恰好在四个方向之一有一个横杠,现在有一人其步长为h,即每一步只能在一个方向上继续上爬至多高度差为h的的横杠,问建造一个杆子,能让人至少沿一个方向上爬到(N-h+1)到N高度的方案数。
范围:
N<=1000,h<=30
解法:
动态规划,DP[I][J][K][L][M]表示当前高度为I,四个方向上离I最近的横杠与I的差为J,K,L,M,其中J,K,L,M=0的话,表示差值大于了h,这样的话J,K,L,M的范围是0-30, 复杂度为9亿,需要继续优化,发现其中一个杆子的差值必然为0/1,那么只要 1000*30*30*30*2的复杂度就够啦,直接DP求解,我使用了一个滚动来优化空间。
(这时候I表示最近造的杆子所在的方向上是否合法,即0/1,如果合法,高度即为1,否则说明高度差曾经大于过h,然后K,L,M表示剩余的三个方向上的高度差值,然后,发现这三个方向上在DP的时候可以随便交换位置竟然也是对的……我一开始在这里卡了很久,不知道怎么转移,最后发现既然表示的是剩下的三个方向的高度差值,那么其顺序是无关的,所以不需要考虑那么多,直接DP即可....orz,果然DP还是练的太少)
代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<iostream>
#include<stdlib.h>
#include<set>
#include<map>
#include<queue>
#include<vector>
#include<bitset>
#pragma comment(linker, "/STACK:1024000000,1024000000")
template <class T>
bool scanff(T &ret){ //Faster Input
char c; int sgn; T bit=0.1;
if(c=getchar(),c==EOF) return 0;
while(c!='-'&&c!='.'&&(c<'0'||c>'9')) c=getchar();
sgn=(c=='-')?-1:1;
ret=(c=='-')?0:(c-'0');
while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
if(c==' '||c=='\n'){ ret*=sgn; return 1; }
while(c=getchar(),c>='0'&&c<='9') ret+=(c-'0')*bit,bit/=10;
ret*=sgn;
return 1;
}
#define inf 1073741823
#define llinf 4611686018427387903LL
#define PI acos(-1.0)
#define lth (th<<1)
#define rth (th<<1|1)
#define rep(i,a,b) for(int i=int(a);i<=int(b);i++)
#define drep(i,a,b) for(int i=int(a);i>=int(b);i--)
#define gson(i,root) for(int i=ptx[root];~i;i=ed[i].next)
#define tdata int testnum;scanff(testnum);for(int cas=1;cas<=testnum;cas++)
#define mem(x,val) memset(x,val,sizeof(x))
#define mkp(a,b) make_pair(a,b)
#define findx(x) lower_bound(b+1,b+1+bn,x)-b
#define pb(x) push_back(x)
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
int pre[2][31][31][31];
int cur[2][31][31][31];
int mod=1000000009;
main(){
int n,h,temp;
scanff(n);
scanff(h);
if(h==1){
printf("%d\n",4);
return 0;
}
pre[1][2][2][2]=4;
int ni,nj,nk,nl;
rep(t,2,n){
mem(cur,0);
rep(i,0,1){
ni=i+1;
if(ni==1||ni==h+1)ni=0;
rep(j,0,h){
nj=j+1;
if(nj==1||nj==h+1)nj=0;
rep(k,0,h){
nk=k+1;
if(nk==1||nk==h+1)nk=0;
rep(l,0,h){
temp=pre[i][j][k][l];
if(temp==0)continue;
nl=l+1;
if(nl==1||nl==h+1)nl=0;
//这时候随意交换I,J,K,L的位置都是对的
//因为DP的内容与顺序无关,最后统计的时候只要看是否为正数
if(i)cur[1][nj][nk][nl]=(cur[1][nj][nk][nl]+temp)%mod;
else cur[0][nj][nk][nl]=(cur[0][nj][nk][nl]+temp)%mod;
if(j)cur[1][ni][nk][nl]=(cur[1][ni][nk][nl]+temp)%mod;
else cur[0][ni][nk][nl]=(cur[0][ni][nk][nl]+temp)%mod;
if(k)cur[1][ni][nj][nl]=(cur[1][ni][nj][nl]+temp)%mod;
else cur[0][ni][nj][nl]=(cur[0][ni][nj][nl]+temp)%mod;
if(l)cur[1][ni][nj][nk]=(cur[1][ni][nj][nk]+temp)%mod;
else cur[0][ni][nj][nk]=(cur[0][ni][nj][nk]+temp)%mod;
}
}
}
}
memcpy(pre,cur,sizeof(cur));
}
int ans=0;
rep(i,0,1)
rep(j,0,h)
rep(k,0,h)
rep(l,0,h){
if(i||j||k||l)ans=(ans+cur[i][j][k][l])%mod;
}
printf("%d\n",ans);
}