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)