Codeforces 1381B Unmerge(序列划分+背包)

题意:给出一个长度为2*n的序列p(1-2*n的整数组成)问是否能由长度为n的a,b数组通过merge(a,b)构成数组p,merge是双指针放在a,b数组起点中,每次取出a[i], b[j]小的,对应指针右移,直到取完。n<2e3

题解:每次都是取出较小的,尝试通过以p【1】的递增序列对p序列划分,例如 3 2 6 1 5 7 8 4划分为【3 2】【6 1 5】 【7】【8 4】,划分为一组的表示该组的数字的必然是在a中,或者b中,则该题可以转化成从这些组中能否取出一些组并且使得这些组的数字有n个,直接跑背包判断可行性即可。

#include <bits/stdc++.h>
#define IO_read ios::sync_with_stdio(false);cin.tie(0)
#define fre freopen("C:\\in.txt", "r", stdin)
#define _for(i,a,b) for(int i=a; i< b; i++)
#define _rep(i,a,b) for(int i=a; i<=b; i++)
#define inf 0x3f3f3f3f
#define lowbit(a) ((a)&-(a))
using namespace std;
typedef long long ll;
template <class T>
void read(T &x)
{
    char c; bool op=0;
    while(c=getchar(), c<'0'||c>'9') if(c=='-') op=1;
    x=c-'0';
    while(c=getchar(), c>='0'&&c<='9') x=x*10+c-'0';
    if(op) x=-x;
}

const int maxn=5e3+5;
int T, n, f[maxn], a[maxn], v[maxn];

int main()
{
    //fre;
    read(T);
    while(T--)
    {
        read(n);
        _rep(i, 1, 2*n) read(a[i]);
        int p=1, cnt=0;
        while(p<=2*n)
        {
            int len=1, tmax=a[p++];
            while(p<=2*n && tmax>a[p]) p++, len++;
            v[++cnt]=len;
        }
        //for(int i=1; i<=cnt; i++) printf("%d ", v[i]);
        for(int i=1; i<=n; i++) f[i]=-inf;
        for(int i=1; i<=cnt; i++)
            for(int j=n; j>=v[i]; j--)
                f[j]=max(f[j], f[j-v[i]]+v[i]);
        printf(f[n]==n? "YES\n":"NO\n");
    }
    return 0;
}

 

posted @ 2020-08-04 17:06  N_Yokel  阅读(195)  评论(0编辑  收藏  举报