1. 程式人生 > 實用技巧 >【Codeforces】#658 D.Unmerge DP

【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;
}