1. 程式人生 > 實用技巧 >Codeforces Round #658 (Div. 2) D. Unmerge (思維,01揹包)

Codeforces Round #658 (Div. 2) D. Unmerge (思維,01揹包)

  • 題意:有兩個陣列\(a\)\(b\),每次比較它們最左端的元素,取小的加入新的陣列\(c\),若\(a\)\(b\)其中一個為空,則將另一個全部加入\(c\),現在給你一個長度為\(2n\)的陣列\(c\),問是否能有兩個長度為\(n\)的陣列\(a\)\(b\)構成.

  • 題解:我們從左向右看\(c\),記一個最大值\(mx\),觀察樣例不難發現,跟隨在\(mx\)後面比\(mx\)小的元素,它們一定來自同一個陣列,比如第三個樣例:

    3 2 6 1 5 7 8 4
    

    \(3,2\)一定來自同一個陣列,\(6,1,5\)一定來自同一個陣列,\(7\)就一個元素,\(8,4\)一定來自同一個陣列,所以我們將它們分段,\((3,2)\)

    ,\((6,1,5)\),\((7)\),\((8,4)\).我們要在這些之間湊出一個元素長度為\(n\)的陣列即可,這裡我們用01揹包來解決,我們揹包的最大容量為\(n\),去看是否能填滿.

  • 程式碼:

    int t;
    int n;
    int a[N];
    vector<int> v;
    int dp[N];
    
    int main() {
        scanf("%d",&t);
         while(t--){
         	scanf("%d",&n);
         	me(dp,0,sizeof(dp));
         	v.clear();
         	for(int i=1;i<=2*n;++i){
         		scanf("%d",&a[i]);
         	}
         	int mx=a[1];
         	int pos=1;
         	for(int i=2;i<=2*n;++i){
         		if(a[i]>mx){
         			v.pb(i-pos);
         			mx=a[i];
         			pos=i;
         		}
         	}
         	v.pb(2*n+1-pos);
         
         	for(int i=0;i<v.size();++i){
         		for(int j=n;j>=v[i];--j){
         			dp[j]=max(dp[j],dp[j-v[i]]+v[i]);
         		}
         	}
         	if(dp[n]==n) puts("YES");
         	else puts("NO");
         	
         }
    	
        return 0;
    }