CF1381B Unmerge

Posted chinesepikaync

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF1381B Unmerge相关的知识,希望对你有一定的参考价值。

Unmerge,题意差不多就是逆向归并排序

手模样例,3 1 2 4 ,发现这个 3 肯定是 a 或 b 的第一个字母,然后假设把 3 放在 a 的第一个,那么 1 放 b 的第一个就不行,只能放 3 后面,2 也是同理,直到 4 才可以放在 b 。按照这个结论去模拟了所有样例,发现没啥问题。于是我们发现,如果选一个数,那么从这个数开始后面,直到第一个比他大的数前为止的数都必须得选。那么这个题就转化成了:

给定一些数,求把他们分成和相等的两组是否可行

可行性dp走起: (f_{i,j}=true/false) 表示使用前 (i) 个数, a 组的数的和减去 b 组的数的和是否可能到达 (j) ,然后转移方程显而易见:

[f_{i,j} leftarrow f_{i-1,j+a_i} | f_{i-1,j-a_i} ]

这个显然可以滚存,然后bitset一下,代码就非常短了

// This code wrote by chtholly_micromaker(MicroMaker)
#include <bits/stdc++.h>
#define reg register
using namespace std;
template <class t> inline void read(t &s)
{
	s=0;
	reg int f=1;
	reg char c=getchar();
	while(!isdigit(c))
	{
		if(c==‘-‘)
			f=-1;
		c=getchar();
	}
	while(isdigit(c))
		s=(s<<3)+(s<<1)+(c^48),c=getchar();
	s*=f;
	return;
}
int a[4000];
inline void work()
{
	int n;read(n);
	n<<=1;
	for(int i=1;i<=n;++i)
		read(a[i]);
	vector<int> dr;
	for(int i=1;i<=n;++i)	// 把问题转化
	{
		reg int pos=i;
		while(pos<n&&a[pos+1]<a[i])
			++pos;
		dr.push_back(pos-i+1);
		i=pos;
	}
	bitset<4000> f;		// 可行性dp
	f[2000]=true;
	for(int i=0;i<(int)dr.size();++i)
		f=(f<<dr[i])|(f>>dr[i]);
	puts(f.test(2000)?"YES":"NO");
	return;
}
signed main(void)
{
	int t;cin>>t;
	while(t--)
		work();
	return 0;
}

以上是关于CF1381B Unmerge的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Round #658 (Div. 2) - D. Unmerge(dp)

Codeforces Round #658 (Div. 2) D. Unmerge(dp)

如何从后台弹出片段

cf 模拟

CF1435 游记

无法解析符号 c882c94be45fff9d16a1cf845fc16ec5