D. Unmerge

https://codeforces.com/contest/1382/problem/D

 

题意:定义两个数组的合并merge(a,b),每次将数组a第一个元素和数组b第一个元素中最小的那个放到数组c中,同时删除那个最小的元素,现在给你一个长度为2*n的排列,问是否能由两个长度为n的数组合并而成

思路:对于长度为2*n的排列,显然是通过一段一段合并得到的,例如(3,2,6,1,5,7,8,4),找到3后面比他大的第一个数6,6后面比他大的第一个数7,7后面比他大的第一个数8,应该分为(3,2),(6,1,5),(7),(8,4)这四段,然后将这四段进行分配,判断能够组成两个长度为n的数组,用01背包判断(背包容量为n,物品的容量和价值都为每一段的长度),判断最后的最大价值是否为n即可

 

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstring>
 4 #include <cstdio>
 5 #include <vector>
 6 
 7 using namespace std;
 8 
 9 typedef long long ll;
10 
11 const int N = 4010;
12 const int INF = 0x3f3f3f3f;
13 
14 int T, n, cnt, a[N], d[N], dp[N];
15 vector<int> p;
16 
17 int main()
18 {
19     // freopen("in.txt", "r", stdin);
20     // freopen("out.txt", "w", stdout);
21     scanf("%d", &T);
22     while (T--) {
23         cnt = 0;
24         p.clear();
25         scanf("%d", &n);
26         for (int i = 1; i <= 2 * n; i++) scanf("%d", &a[i]);
27         int imax = 0;
28         for (int i = 1; i <= 2 * n; i++) {
29             if (a[i] < imax) continue;
30             imax = a[i];
31             p.push_back(i);
32            // printf("i:%d\n",i);
33         }
34         p.push_back(2 * n + 1);
35         for (int i = 1; i < p.size(); i++)
36             d[++cnt] = p[i] - p[i - 1];
37         for (int i = 1; i <= n; i++) dp[i] = -INF;
38         for (int i = 1; i <= cnt; i++)
39             for (int k = n; k >= d[i]; k--)
40                 dp[k] = max(dp[k], dp[k - d[i]] + d[i]);
41         printf(n == dp[n] ? "YES\n" : "NO\n");
42       //  printf("dp:%d\n",dp[n]);
43     }
44     return 0;
45 }
View Code

 

posted @ 2020-07-30 16:20  古比  阅读(175)  评论(0编辑  收藏  举报