Codeforces Round #658 (Div. 2) D. Unmerge (01背包)

题目链接: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;	
} 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值