原题链接:https://codeforces.ml/contest/1382/problem/D

 

题目大意:

给定两个数组,每次选取两个数组剩余部分的头一个数字中较小的那个入队,合并成一个新的数组

现有一个长度为2n的数组,判断它是否能由两个长度为n的数组合并而成

 

思路:

合并成的数组中某个数字和后面接连着的多个小于它的数必定来自同一个数组

这样把数组拆分成几段,如果能用这几段拼成长度刚好为n的数组就输出YES,否则就输出NO

经典的dp问题,做的时候真没看出来

 

代码:

#define _USE_MATH_DEFINES
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <math.h>
#include <ctype.h>
#include <vector>
#include <stack>
#include <map>
#include <set>
#include <algorithm>
#include <iostream>
#include <limits.h>
#include <iomanip>
#include <queue>
#include <functional>
#define el '\n'
#define M 100005
const long long N = 1e9+7;
#define ll long long
using namespace std;

int dp[2005];
int a[4005];
int b[2005];
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    
    //freopen("test14.in","r",stdin);
    //freopen("test14.out","w",stdout);
    int t;
    cin>>t;
    while(t--){
        int n;
        cin>>n;
        int m;
        int cnt=0;
        int len;
        for(int i=0;i<2*n;i++){
            cin>>a[i];
            if(!i){
                m=a[i];
                len=1;
            }
            else{
                if(a[i]<m){
                    len++;
                }
                else{
                    m=a[i];
                    b[cnt++]=len;
                    len=1;
                }
            }
        }
        b[cnt++]=len;
        int f=1;
        for(int i=0;i<cnt;i++){
            if(b[i]>n){
                f=0;
                break;
            }
        }
        if(!f){
            cout<<"NO"<<el;
            continue;
        }
            memset(dp,0,sizeof(dp));
        dp[0]=1;
        for(int i=0;i<cnt;i++){
            for(int j=n;j>=b[i];j--){
                dp[j]=dp[j]||dp[j-b[i]];
            }
        }
        cout<<(dp[n]?"YES\n":"NO\n");
    }
    return 0;
}

 

posted on 2020-07-31 22:57  保护不保护保护  阅读(117)  评论(0)    收藏  举报