题目链接:https://codeforces.ml/contest/1382/problem/D
题意:定义两个数组的合并merge(a,b),每次将数组a第一个元素和数组b第一个元素中最小的那个放到数组c中,同时删除那个最小的元素,现在给你一个长度为2*n的排列,问是否能由两个长度为n的数组合并而成。
题解:通过观察可以发现这一段序列由若干个子段组成,例如3 1 2 4可以由3 1 2 和 4组成,其分法是以最大值为分割点,可以简单的证明一下,若将一段中小的放到另一个数组b中,则该小的数必然排在大的数字前,也就是分解成3 1 和 2 4那么2一定会排在3的前面。得到这个结论后问题就转化成有若干段,问是否能组成长度为n的一段,因此跑一遍01背包即可,体积和价值都是某一段的长度。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5000;
int f[maxn],a[maxn];
typedef struct{
int w,v;
}goods;
goods g[maxn];
int main()
{
int T;cin>>T;
while(T--){
int n;cin>>n;int cnt=0;
for(int i=1;i<=2*n;i++) cin>>a[i];
memset(f,0,sizeof(f));
int mx=a[1];int num=1;
for(int i=2;i<=2*n;i++){
if(a[i]<mx) num++;
else{
g[++cnt].w=num,g[cnt].v=num;
num=1;mx=a[i];
}
}
g[++cnt].w=num,g[cnt].v=num;
for(int i=1;i<=cnt;i++){
for(int j=n;j>=g[i].w;j--)
f[j]=max(f[j],f[j-g[i].w]+g[i].v);
}
if(f[n]==n) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}