【Codeforces】#658 D.Unmerge DP
D.Unmerge
题意
定义 \(merge(a,b)\) :
a,b是两个长度均为 n 的数组.
如果 \(a_1 < b_1\) \(merge(a,b)\) = \(a_1\) + \(merge(a_2+ a_3 + a_4 ... , b)\)
如果 \(a_1 > b_1\) \(merge(a,b)\) = \(b_1\) + \(merge( a , b_2+b_3+b_4+...)\)
给出一个正整数 n ,以及长度为 2 * n 的全排列,问这个全排列是否可能是两个长度为 n 的数组merge 得到
思路
写一下就会发现:
如果第 i 个数字是 x ,第一个下标大于 i ,并且 \(p_j > x\) (\(p_j\) 表示下标为 j 的数字) 的 j
这 j - i 个数字应该来自一个数组。
那么我们统计应该来自一个数组的数字个数,进行 DP ,判断能否形成长度为 n 的数组即可。
代码
/*
* @Autor: valk
* @Date: 2020-07-17 16:50:40
* @LastEditTime: 2020-08-17 11:34:55
* @Description: 如果邪恶 是 华丽残酷的乐章 它的终场 我会亲手写上 晨曦的光 风干最后一行忧伤 黑色的墨 染上安详
*/
#include <bits/stdc++.h>
#define fuck system("pause")
#define emplace_back push_back
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int mod = 1e9 + 7;
const int seed = 12289;
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int N = 2e5 + 10;
int arr[N], brr[N], dp[N];
int main()
{
int _;
scanf("%d", &_);
while (_--) {
int n, cnt = 0;
scanf("%d", &n);
n *= 2;
for (int i = 1; i <= n; i++) {
scanf("%d", &arr[i]);
}
for (int i = 1; i <= n;) {
int j = i;
while (j <= n && arr[j] <= arr[i])
j++;
brr[++cnt] = j - i;
i = j;
}
memset(dp, 0x8f, sizeof(dp));
dp[0] = 1;
for (int i = 1; i <= cnt; i++) {
for (int j = 2000; j >= brr[i]; j--) {
dp[j] = max(dp[j], dp[j - brr[i]]);
}
}
if (dp[n / 2] == 1) {
printf("YES\n");
} else {
printf("NO\n");
}
}
// fuck;
return 0;
}