Codeforces Round #658 (Div. 2) D. Unmerge预处理+01背包dp

补题,题目链接:Codeforces Round #658 (Div. 2) D. Unmerge

题目描述

Let a and b be two arrays of lengths n and m, respectively, with no elements in common. We can define a new array merge(a,b) of length n+m recursively as follows:

If one of the arrays is empty, the result is the other array. That is, merge(∅,b)=b and merge(a,∅)=a. In particular, merge(∅,∅)=∅.
If both arrays are non-empty, and a1<b1, then merge(a,b)=[a1]+merge([a2,…,an],b). That is, we delete the first element a1 of a, merge the remaining arrays, then add a1 to the beginning of the result.
If both arrays are non-empty, and a1>b1, then merge(a,b)=[b1]+merge(a,[b2,…,bm]). That is, we delete the first element b1 of b, merge the remaining arrays, then add b1 to the beginning of the result.
This algorithm has the nice property that if a and b are sorted, then merge(a,b) will also be sorted. For example, it is used as a subroutine in merge-sort. For this problem, however, we will consider the same procedure acting on non-sorted arrays as well. For example, if a=[3,1] and b=[2,4], then merge(a,b)=[2,3,1,4].

A permutation is an array consisting of n distinct integers from 1 to n in arbitrary order. For example, [2,3,1,5,4] is a permutation, but [1,2,2] is not a permutation (2 appears twice in the array) and [1,3,4] is also not a permutation (n=3 but there is 4 in the array).

There is a permutation p of length 2n. Determine if there exist two arrays a and b, each of length n and with no elements in common, so that p=merge(a,b).

输入描述

The first line contains a single integer t (1≤t≤1000) — the number of test cases. Next 2t lines contain descriptions of test cases.

The first line of each test case contains a single integer n (1≤n≤2000).

The second line of each test case contains 2n integers p1,…,p2n (1≤pi≤2n). It is guaranteed that p is a permutation.

It is guaranteed that the sum of n across all test cases does not exceed 2000.

输出描述

For each test case, output “YES” if there exist arrays a, b, each of length n and with no common elements, so that p=merge(a,b). Otherwise, output “NO”.

题意

merge(a,b)操作:两个数组中,把较小的元素依次拿出排序。
现有一个2*n的数组p,问你是否存在两个长度恰好为n的数组可以通过merge操作生成数组p。

题解

可以理解成,满足merge操作的子串,是否能把长度不一样的子串拼装成两个大小为n的数组。
某一个数及它后面比它小的数,必定属于同个数组,可以预处理各个子串的长度,若出现长度大于n的片段肯定是NO,再通过01背包dp选择判断。

#pragma GCC optimize(2)
#include<bits/stdc++.h> 
using namespace std;
#define endl "\n"
const int MAX=1e4+7;
int a[MAX],dp[MAX];
int main(){
    ios_base::sync_with_stdio(0);cin.tie(0);
   int t;cin>>t;
   while(t--)
   {
   		int n;cin>>n;
   		int mx=0,x=0,l=1,cnt=0;
   		cin>>x;mx=x;
   		for(int i=1;i<2*n;i++){
   			cin>>x;
   			if(x<mx) l++;
			else{
				a[cnt++]=l;
				mx=x;l=1;	
			}
		}
		a[cnt++]=l;
   		int f=0;
   		for(int i=0;i<cnt;i++){
   			if(a[i]>n){
   				f=1;break;	
			}	
		}
   		if(f){
   			cout<<"NO"<<endl;continue;	
		}
		memset(dp,0,sizeof(dp));
		dp[0]=1;
		for(int i=0;i<cnt;i++)
		for(int j=n;j>=a[i];j--)
		 dp[j]=dp[j]||dp[j-a[i]];
		cout<<(dp[n]?"YES":"NO")<<endl; 
   }
   return 0;
} 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值