CF1381B Unmerge(01背包)
挺有意思,主要是仔细观察这个数列和题目所给的信息,CF题目的解法经常就隐藏在题目信息和案例中
首先我们肯定是关注题目所给的merge的定义,发现首位是一个与其他不同的特殊信息。其实不难发现,如果一个数能成为某个小数组的开头来合并的话
在他后面的比他小的数,一定要跟他成为一个集合。否则不成立,因为如果当前作为B开头,那么之后不大于他的肯定不行,并且显然他作为a开头,后面的也不能作为b开头,因为这样无法得到正确答案
因此我们按照这个思想划分,之后做一遍01背包观察是否能组成n就行
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<ll,ll> pll; const int N=2e6+10; const int inf=0x3f3f3f3f; const int mod=1e9+7; int p[N]; int a[N]; int st[N]; int cnt[N]; int f[N]; int main(){ ios::sync_with_stdio(false); int t; cin>>t; while(t--){ int n; cin>>n; int i; for(i=1;i<=2*n;i++){ st[i]=0; f[i]=0; } for(i=1;i<=2*n;i++){ cin>>p[i]; } int idx=0; int now=2*n; int num=2*n; int last=2*n; while(num){ int i; int tmp=0; for(i=1;i<=last;i++){ if(p[i]==now){ tmp=i; } } int res=0; for(i=tmp;i<=last;i++){ res++; st[p[i]]=1; num--; } last=tmp-1; cnt[++idx]=res; while(now&&st[now]) now--; } f[0]=1; for(i=1;i<=idx;i++){ for(int j=n;j>=cnt[i];j--){ f[j]|=f[j-cnt[i]]; } } if(f[n]){ cout<<"YES"<<endl; } else{ cout<<"NO"<<endl; } } return 0; }
没有人不辛苦,只有人不喊疼