1. 程式人生 > 實用技巧 >CF1381B Unmerge(01揹包)

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; }
View Code