【JOI】JOISC2020R1_T1building_构造

题面

大意就是:给两个\(2n\)数组\(A,B\),要生成一个单调不降序列\(C\),使得\(C_i=A_i\)\(C_i=B_i\)。并且有恰好\(n\)个位置选择了\(C_i=A_i\)。任意一种方案。

题解

现场得分:100/100

  • \(A\)数组为第0个数组,\(B\)数组为第1个数组。
  • 记dp:\(f_{i,0/1,0/1}\),表示从\(1\)\(i\),第\(i\)个当中用的是第0/1个数组,尽可能地多用0/1,最多能用多少个。
  • 这个很好转移
  • 然后有个结论:如果\(n\leq min(f_{2n,0,0},f_{2n,0,1})\)或者\(n\leq min(f_{2n,1,0},f_{2n,1,1})\)就一定有解。感性地理解,就是你尽可能选0,可以超过一半;尽可能选1,也可以超过一半。
    • 为什么?发现其中关键是能否在这个框出的区间里每个值都取到。(最多\(x\)个,最少\(y\)个,那么\([y,x]\)每个值都能取到)。
    • 考虑相邻两个的关系。
    • 先简化一下,我们记\(min_i=min(a_i,b_i),max_i=max(a_i,b_i)\)把第\(i\)个位置上的看成一个\(p_i=[min_i,max_i]\)的区间,发现这是不影响的。
    • 如果\(p_i\)\(p_{i+1}\)相离,显然不影响。
    • 如果\(p_i\)\(p_{i+1}\)有包含关系,显然就没有自由选择余地了,不影响。
    • 如果\(p_i\)\(p_{i+1}\)交叉,但是\(min_{i+1}<min_{i}\),显然就没有自由选择余地了,不影响。
    • 剩下一种情况:\(min_i\leq min_{i+1}\leq max_i\leq max_{i+1}\)。你会发现这是两个递增序列,你随时可以从底下一个跳到上面一个,因此也是满足的。
    • 我们就证完了
  • 然后考虑怎么构造
  • 我们倒着跑一遍,每时每刻都保持尽量选0和尽量选1的最大个数始终大于等于\(n\)

代码

#include<bits/stdc++.h>
#define LL long long
#define MAXN 500100
using namespace std;
template<typename T>void Read(T &cn)
{
    char c;int sig = 1;
    while(!isdigit(c = getchar()))if(c == '-')sig = -1; cn = c-48;
    while(isdigit(c = getchar()))cn = cn*10+c-48; cn*=sig;
}
template<typename T>void Write(T cn)
{
    if(cn < 0) {putchar('-'); cn = 0-cn; }
    int wei = 0; T cm = 0; int cx = cn%10; cn/=10;
    while(cn)cm = cm*10+cn%10,cn/=10,wei++;
    while(wei--)putchar(cm%10+48),cm/=10;
    putchar(cx+48);
}
int n;
int a[MAXN*2+1], b[MAXN*2+1];
int ans[MAXN*2+1];
int f[MAXN*2+1][2][2];
void getit(int a[], int n) {for(int i = 1;i<=n;i++) Read(a[i]); }
void geng(int cn, int cm, int cx, int cy) {if(cy > f[cm][cx][cn]) f[cm][cx][cn] = cy; }
int nong()
{
    for(int i = 0;i<=1;i++) for(int j = 0;j<=1;j++) f[1][i][j] = (i==j);
    for(int i = 2;i<=n*2;i++)
    {
        for(int j = 0;j<=1;j++) for(int k = 0;k<=1;k++) f[i][j][k] = -n*2;
        if(a[i] >= a[i-1]) geng(0,i,0,f[i-1][0][0]+1), geng(1,i,0,f[i-1][0][1]);
        if(a[i] >= b[i-1]) geng(0,i,0,f[i-1][1][0]+1), geng(1,i,0,f[i-1][1][1]);
        if(b[i] >= a[i-1]) geng(0,i,1,f[i-1][0][0]), geng(1,i,1,f[i-1][0][1]+1);
        if(b[i] >= b[i-1]) geng(0,i,1,f[i-1][1][0]), geng(1,i,1,f[i-1][1][1]+1);
    }
    int lei1 = 0, lei2 = 0, lst = max(a[2*n],b[2*n])+1;
    for(int i = n*2;i>=1;i--)
    {
        if(lei1 + f[i][0][0] >= n && lei2 + f[i][0][1] >= n && a[i] <= lst) {lei1++; ans[i] = 0; lst = a[i]; continue; }
        if(lei1 + f[i][1][0] >= n && lei2 + f[i][1][1] >= n && b[i] <= lst) {lei2++; ans[i] = 1; lst = b[i]; continue; }
        return 0;
    }
    return 1;
}
int main()
{
    Read(n); 
    getit(a,n*2); getit(b,n*2);
    if(!nong()) {puts("-1"); return 0; }
    for(int i = 1;i<=n*2;i++) putchar('A'+ans[i]); puts("");
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/czyarl/p/12535922.html