详细题目见:http://7xjob4.com1.z0.glb.clouddn.com/0f10204481da21e62f8c145939e5828e
思路:记dp[i][j]表示第i个木板尾部在j的方案数。那么对于i+1,可以分三种情况讨论,一种是i+1的头部在第i根整段的左边,一种是在右边,还有在中间,中间的有两种情况,其他都只有一种,然后就可以转移了。
转载 http://blog.csdn.net/kirito_acmer/article/details/50189591
关键是只记录尾部就好,因为上一层的尾部情况很多 所以都可以放在第二维里面
然后就是状态转移,就是把上一层尾部的数量,如果更新到,那么判断当前的钉子相对于上一层木板的位置,然后选择对当前木块尾部的位置进行状态转移
#include <bits/stdc++.h>
#define maxn 2050
using namespace std;
typedef long long ll;
ll num[maxn];
ll dp[maxn][maxn];
const int mod = 2147483647;
int main()
{
int n;
cin>>n;
for(int i=0;i<=n;i++) cin>>num[i];
dp[0][num[0]]=1; //第一个尾部固定的点为1
//然后更新的是dp[1][num[0]]的尾部
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n+1;j++)
{
if(dp[i-1][j]) //j是尾部,上一块木头的尾部。
{
int l=num[i-1],r=j; //上一块木板的位置
if(l>r) swap(l,r);
if(num[i]<=l) //如果订的地方在上一个木板的左边 那么,只能更新右边
{
dp[i][r]=(dp[i][r]+dp[i-1][j])%mod;
}
else if(num[i]>=r) //如果钉的地方在上一个木板的右边,那么只能更新左边
{
dp[i][l]=(dp[i][l]+dp[i-1][j])%mod;
}
else //如果是中间 两边都可以钉
{
dp[i][r]=(dp[i][r]+dp[i-1][j])%mod;
dp[i][l]=(dp[i][l]+dp[i-1][j])%mod;
}
}
}
}
ll sum=0;
for(int j=1;j<=n+1;j++)
{
sum=(sum+dp[n][j])%mod;
}
printf("%lld\n",sum );
}