题目描述
有 n (编号 0 至
n−1 )个学生组成的合唱队,已知他们的身高,且没有相同的。现在要你来负责给他们排队,使得他们的身高是“山峰”型的。所谓的“山峰型”是指,存在一个下标 j (0<j<n−1 ), 使得下标从 0 到 j 的人的身高是递增的,从下标是j 到 n−1 的人的身高是递减的。似曾相识?那加个条件吧,我们还要求任意相邻两个人的身高的差距不能超过 k 。请问有多少种不同的“山峰”型队列?答案模1234567891。如果没有合法的“山峰”型队列,输出0。
输入格式 1780.in
多组测试数据。
第一行:一个整数r , 表示有 r 组测试数据。1≤r≤5 。
每组测试数据格式如下:
第一行: n 和k 。 1≤n≤50 , 1≤k≤1000000000 。
第二行: n 个正整数,指身高,每个正整数不超过 1000000000。
输出格式 1780.out
共
r 行,每行一个整数表示有多少种不同的“山峰”型队列。
输入样例 1780.in
2
4 10
1 5 10 4
9 44
96 29 21 90 46 77 31 63 79
输出样例 1780.out
6
126
样例解释
第一组测试数据解释,6个不同合法“山峰”队列分别是:
{1, 4, 10, 5}, {1, 5, 10, 4}, {1, 10, 5, 4}
{4, 5, 10, 1}, {4, 10, 5, 1}, {5, 10, 4, 1}
这题看得我挺头疼的,想在原数组直接搞 DP。但一时要想着身高大小关系,一时又要考虑身高差值。其实后来想想,分析问题的时候,应该把一些条件“强制”一下,比如先把身高排序,这样只考虑差值的问题就可以了。其实这是简化问题的基本策略,但我考试时居然没有意识到,唉。
首先明确一点,既然在最终的队形中是要让 0 ~
j
单调递增,意味着前面的值都比
我们应该如何描述一个队形呢?既然中心点已经确定,那么剩下的无非就是最左边和最右边。不妨用
f[i][j][k]
表示排序后的前
i
个人组成一种合法队列,其中左、右端点分别为
可以想象这样的情景:因为这个队列从中间往两边是越来越低的,那么我们就可以看作,在确定了最高的中心点之后,其他人从高到低不断往两边插入值。
在这种理解基础上,就不难得到
上述两个式子分别对应:把第 i 个人插入在队列最左端和最右端。
那么初始状态就有 f[1][1][1] = f[2][1][2] = f[2][2][1] = 1,要求的答案为
解释一下,最后一定是取完了
n
个点,最低的点
这题还有少一维状态的方法,跟之前“多滋味的咖啡”、“中国移动”有异曲同工之妙。但由于最近测试多,题目多,要写的笔记也多,优化暂时还没时间写。
参考代码:
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <functional>
using namespace std;
const int mod = 1234567891;
const int maxn = 100;
int h[maxn];
long long dp[maxn][maxn][maxn];
int main(void) {
freopen("1780.in", "r", stdin);
freopen("1780.out", "w", stdout);
int r;
scanf("%d", &r);
while (r--) {
int n, k;
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i++) scanf("%d", &h[i]);
sort(h + 1, h + n + 1, greater<int>());
memset(dp, 0, sizeof dp);
dp[1][1][1] = dp[2][1][2] = dp[2][2][1] = 1;
for (int i = 3; i <= n; i++)
for (int a = 1; a < i; a++)
for (int b = 1; b < i; b++) {
if (h[a] - h[i] <= k) (dp[i][i][b] += dp[i - 1][a][b]) %= mod;
if (h[b] - h[i] <= k) (dp[i][a][i] += dp[i - 1][a][b]) %= mod;
}
long long ans = 0;
for (int i = 2; i <= n; i++) (ans += (dp[n][n][i] + dp[n][i][n]) % mod) %= mod;
printf("%lld\n", ans);
}
return 0;
}