codeforces 14e dp

题意:现在有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;
}

猜你喜欢

转载自blog.csdn.net/qq_38759433/article/details/86559949