Codeforces Round #504 D. Array Restoration

Codeforces Round #504 D. Array Restoration

题目描述:有一个长度为\(n\)的序列\(a\),有\(q\)次操作,第\(i\)次选择一个区间,将区间里的数全部改为\(i\),序列\(a\)的每个位置至少被改一次。得到最终的序列,然后将序列里的某些位置变成\(0\),输出一种可能的置零之前的最终序列,或无解。

solution

求出每种数字最长的染色区间,按这个区间染色,记下没出现的数字。染色后如果存在\(0\)联通块,则用没出现的数字从大到小染色(一个联通块一种颜色),不够则无解,最后判断最大的数字\(q\)是否用上了,如果没有,则在原序列中找一个\(0\)变成\(q\)即可,若原序列没有\(0\),则无解。

时间复杂度:\(O(nlogn)\)

#include <bits/stdc++.h>
using namespace std;

const int maxn=int(2e5)+100;

struct mes
{
    int x, y, v;
};

int n, m;
int a[maxn], ans[maxn];
int BIT[maxn];
int tree[maxn*4], mark[maxn*4];
bool vis[maxn];
vector<int> zero;
pair<int, int> block[maxn];
mes dat;

void read()
{
    scanf("%d%d", &n, &m);
    for (int i=1; i<=n; ++i) scanf("%d", &a[i]);
}
void insert(int cur, int v)
{
    for (; cur<=m; cur+=(-cur)&cur) BIT[cur]=max(BIT[cur], v);
}
int ask(int cur)
{
    int w=0;
    for (; cur; cur-=(-cur)&cur) w=max(w, BIT[cur]);
    return w;
}
void down(int cur)
{
    tree[cur<<1]=tree[cur<<1 | 1]=mark[cur];
    mark[cur<<1]=mark[cur<<1 | 1]=mark[cur];
    mark[cur]=0;
}
void updata(int cur, int L, int R)
{
    if (dat.x>R || dat.y<L) return;
    if (dat.x<=L && R<=dat.y)
    {
        tree[cur]=dat.v;
        mark[cur]=dat.v;
        return;
    }
    int mid=(L+R)>>1;
    if (mark[cur]) down(cur);
    updata(cur<<1, L, mid);
    updata(cur<<1 | 1, mid+1, R);
}
int get(int cur, int L, int R)
{
    if (L==R) return tree[cur];
    int mid=(L+R)>>1;
    if (mark[cur]) down(cur);
    if (dat.x<=mid) return get(cur<<1, L, mid);
    else return get(cur<<1 | 1, mid+1, R);
}
void solve()
{
    for (int i=1; i<=n; ++i)
    {
        if (a[i]==0) continue;
        if (!vis[a[i]]) block[a[i]].first=ask(a[i]-1);
        vis[a[i]]=true;
        insert(a[i], i);
    }
    for (int i=1; i<=m; ++i) BIT[i]=0, vis[i]=false;
    for (int i=n; i; --i)
    {
        if (a[i]==0) continue;
        if (!vis[a[i]]) block[a[i]].second=n-ask(a[i]-1)+1;
        vis[a[i]]=true;
        insert(a[i], n-i+1);
    }
    for (int i=1; i<=m; ++i)
        if (!vis[i]) zero.push_back(i);
        else
        {
            dat.x=block[i].first+1;
            dat.y=block[i].second-1;
            dat.v=i;
            updata(1, 1, n);
        }

    for (int i=1; i<=n; ++i)
    {
        dat.x=dat.y=i;
        ans[i]=get(1, 1, n);
    }
    for (int i=1; i<=n; ++i)
        if (a[i]!=0 && a[i]!=ans[i])
        {
            printf("NO\n");
            return;
        }

    for (int i=1; i<=n; )
    {
        if (ans[i]!=0) { ++i; continue; }
        if (zero.size()==0)
        {
            puts("NO");
            return;
        }
        int j=i;
        while (j<=n && a[j]==0) ++j;
        for (int k=i; k<j; ++k) ans[k]=zero.back();
        zero.pop_back();
        i=j;
    }
    if (!zero.empty() && zero.back()==m)
    {
        int idx=0;
        for (int i=1; i<=n; ++i)
            if (a[i]==0)
            {
                idx=i;
                break;
            }
        if (idx==0)
        {
            puts("NO");
            return;
        }
        ans[idx]=m;
    }
    puts("YES");
    for (int i=1; i<=n; ++i) printf("%d ", ans[i]);
}
int main()
{
    read();
    solve();
    return 0;
}

原文地址:https://www.cnblogs.com/GerynOhenz/p/9498768.html

时间: 2024-08-28 03:27:37

Codeforces Round #504 D. Array Restoration的相关文章

Round #504 D. Array Restoration .

题目:http://codeforces.com/contest/1023 对于一个长度n的数组进行q次查询,i从1到q,第i次将任意一段连续的部分全部染成i. 最后得到的数组中可能会存在"污点"0.即最后对数组的任意子集set为0. 给出n和q,以及带污点的长为n的数组,判断是否能将其还原成没有0的合理数组. 如果可以则输出任意一合理数组. 思路:先统计每个数的出现的最左位置和最右位置,然后从q到1查询,判断q的最左到最右中间有没有不合理的数(小于q). 因为一定会有q次查询所有最后

Codeforces Round #504 (rated, Div. 1 + Div. 2, based on VK Cup 2018 Final) A. Single Wildcard Pattern Matching B. Pair of Toys C. Bracket Subsequence D. Array Restoration-区间查询最值(RMQ(ST))

Codeforces Round #504 (rated, Div. 1 + Div. 2, based on VK Cup 2018 Final) A. Single Wildcard Pattern Matching 题意就是匹配字符的题目,打比赛的时候没有看到只有一个" * ",然后就写挫了,被hack了,被hack的点就是判一下只有一个" * ". 1 //A 2 #include<iostream> 3 #include<cstdio&g

Educational Codeforces Round 21 D. Array Division

题目链接:Educational Codeforces Round 21 D. Array Division 题意: 给你n个数,现在你可以改变1<=个数的位置,然后问你是否存在有一个k,使得sum(a[i])(1<=i<=k)==sum(a[j])(k+1<=j<=n) 题解: 分析: 如果需要将一个数移动,无非就是将这个数从第一部分移到第二部分,或者从第二部分移到第一部分. 所以,我们只需要开两个map来记录一下两部分有哪些数. 当两部分的差值/2等于其中一部分的一个数时

Codeforces Round #504 (rated, Div. 1 + Div. 2, based on VK Cup 2018 Final) D. Array Restoration

D. Array Restoration time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output Initially there was an array aa consisting of nn integers. Positions in it are numbered from 11 to nn. Exactly qq querie

codeforces Round 63-div2-D.Beautiful Array(线性动归)

原题地址 D. Beautiful Array You are given an array aa consisting of nn integers. Beauty of array is the maximum sum of some consecutive subarray of this array (this subarray may be empty). For example, the beauty of the array [10, -5, 10, -4, 1] is 15, a

Codeforces Round #504 (rated, Div. 1 + Div. 2, based on VK Cup 2018 Final)

考场上只做出了ABDE C都挂了... 题解: A 题解: 模拟 判断前面一段是否相同,后面一段是否相同,长度是否够(不能有重叠) Code: 1 #include<stdio.h> 2 #include<cstring> 3 #include<cstdlib> 4 #include<algorithm> 5 #include<vector> 6 #include<map> 7 #include<set> 8 #inclu

Codeforces Round #504 E - Down or Right 交互题

1023E 题意: 交互题.在一个有障碍地图中,问如何走才能从(1,1)走到(n,n),只能向右或者向左走.每次询问两个点,回复你这两个点能不能走通. 思路: 只用最多2*n-2次询问.从(1,1),能向右走就向右走,不能就向下走,直到走到斜对角线上.从(n,n)出发,能向上走就向上走,不能就向左走,直到走到斜对角线上. 因为保证有路,所以最后输出(1,1)出发的正向路径,加上从(n,n)出发的反向路径. #include <algorithm> #include <iterator&g

$Codeforces\; Round\; 504\; (Div.2)$

宾馆的\(\rm{wifi}\)也太不好了,蹭的\(ZZC\)的热点才打的比赛(感谢\(ZZC\)) 日常掉rating-- 我现在是个\(\color{green}{pupil}\)-- 因为我菜,所以还是只写了前三道题 题解 \(\mathcal{A.Single\; Wildcard\; Pattern\; Matching}\) 题目大意:有点长,不想翻译了qwq 我能说第一题是前三道题中最难的么--各种特判,各种被卡,最后交了4遍也没做出来(我太蒟了 QAQ) 反复修改后的冗杂的AC代

Educational Codeforces Round 23 D. Imbalanced Array(单调栈)

题目链接:Educational Codeforces Round 23 D. Imbalanced Array 题意: 给你n个数,定义一个区间的不平衡因子为该区间最大值-最小值. 然后问你这n个数所有的区间的不平衡因子和 题解: 对每一个数算贡献,a[i]的贡献为 当a[i]为最大值时的 a[i]*(i-l+1)*(r-i+1) - 当a[i]为最小值时的a[i]*(i-l+1)*(r-i+1). 计算a[i]的l和r时,用单调栈维护.具体看代码,模拟一下就知道了. 然后把所有的贡献加起来.