题意:现在有n个点在坐标轴上依次排列,他们坐标为(1,y1),(2,y2),(3,y3),…,(n,yn),你现在的目标就是要在如上n个点中求出产生t个驼峰,t-1个驼谷的方案数,同时满足x1−>x2必须为上升xn−1−>xn必须为下降。
注意,不能出现与x轴平行的线段,所有纵坐标1<=yi<=41<=yi<=4(1<=i<=n)
题解:f[x][t][i][f]表示前x条线段,产生t个驼峰,线段右端点高度为i,该线段方向为f(0下降,1上升)的方案数。 因为要判断波峰,还需要知道左端点,不妨设为p
①当f=1时,(p< j)
这种状态和前面状态是构成不了驼峰的,只能传递信息,所以前面和后面产生驼峰数是一样的,那么这种状态的状态转移方程就可以得出了:
f[x][t][i][1]=sum(f[x−1][t][j][1]+f[x−1][t][j][0])
②当f=0时,(p> j)
这种状态只有与向上的线段才能构成驼峰
状态转移方程就是:
f[x][t][i][0]=sum(f[x−1][t][j][0]+f[x−1][t−1][j][1])
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXY = 5;
const int MAXX = 20;
const int MAXT = 10;
const int INF = 0x3f3f3f3f;
int read(){
int f = 1, x = 0; char s = getchar();
while(s < '0' || s > '9'){if(s == '-')f = -1; s = getchar();}
while(s >= '0' && s <= '9'){x = x * 10 + s - '0'; s = getchar();}
return x * f;
}
int n, f[MAXX + 5][MAXT + 5][MAXY + 5][2];
int main(){//f[x][t][i][f]:第x个线段,有t个驼峰,高度为i
//(x-1)->x点波动状态为f(0为下降,1为上升)
int n = read(), T = read();
for(int i = 1; i <= 4; i ++)
f[0][0][i][0] = 1;
for(int x = 1; x < n; x ++)
for(int t = 0; t <= T; t ++)
for(int i = 1; i <= 4; i ++)
for(int j = 1; j <= 4; j ++){
if(j < i)//情况①
f[x][t][i][1] += f[x - 1][t][j][1] + f[x - 1][t][j][0];
else if(j > i && t && x != 1)//情况②
f[x][t][i][0] += f[x - 1][t][j][0] + f[x - 1][t - 1][j][1];
}
int sum = 0;
for(int i = 1; i <= 4; i ++)
sum += f[n - 1][T][i][0];
printf("%d\n",sum);
return 0;
}