D. Array Restoration

题目链接:https://codeforces.com/contest/1023/problem/D

题意:

给出一个序列,现在要求对一个全为0的序列执行q次操作,每次操作都要选定一段区间然后将区间上面的值变为i(i为操作的次数)。最终使得0序列变为之前给出的序列。

原序列中如果存在0,那么说明这个值是任意的。

最后要求输出经过q次操作之后的序列。

题解:

我们首先可以想到不可行的情况:在原序列中若存在一个数a,假设其出现次数大于1,那么两端为a的中间区间部分,是没有值比a小的。

还有一种情况也不可行,就是原序列中没有0且最大值小于q。

当把这两种情况排除过后,就是可行的情况了,之后输出方案就好了。

输出方案的时候还要解决0的问题,我的解决方案是让0等于其右边或左边的数,我是将一段连续的0缩点后进行处理的。

代码如下:

#include <bits/stdc++.h>
#define pii pair<int,int>
#define INF 99999999
using namespace std; const int N = 2e5+;
int n,q;
int a[N],cnt[N];
struct node{
int l,r;
}z[N],All[N];
int f[N][];
vector <int> vec[N];
int main(){
cin>>n>>q;
int num = ,mx=;
a[]=-;a[n+]=-;
for(int i=;i<=n;i++){
scanf("%d",&a[i]);
mx=max(mx,a[i]);
if(a[i]==&&a[i-]!=){
num++;
}
if(a[i]==){
cnt[i]=num;
if(a[i-]!=) z[num].l=i-;
}else if(a[i-]==) z[num].r=i;
vec[a[i]].push_back(i);
}
if(a[n]==) z[num].r=n+;
int flag = ;
for(int i=;i<=n;i++){
if(a[i]== || vec[a[i]].size()<=) continue ;
int len = vec[a[i]].size()-;
All[a[i]].l=vec[a[i]][];
All[a[i]].r=vec[a[i]][len];
}
for(int i=;i<=n;i++) for(int j=;j<=;j++) f[i][j]=INF;
for(int i=;i<=n;i++) f[i][]=(a[i]== ? INF : a[i]);
for(int i=;i<=n;i++)
for(int j=;j<=;j++)
f[i][j]=min(f[i][j-],f[i+(1ll<<(j-))][j-]);
for(int i=;i<=n;i++){
if(vec[a[i]].size()<=) continue ;
int l = All[a[i]].l,r = All[a[i]].r;
l++;r--;
int K = log((r-l+));
int mn = min(f[l][K],f[r-(<<K)+][K]);
if(mn<a[i]){
flag=;
break ;
}
}
int ok=;
if(q>mx) ok=;
if(ok) for(int i=;i<=n;i++){
if(a[i]==){
a[i]=q;
ok=;
break ;
}
}
if(flag||ok==) cout<<"NO";
else{
cout<<"YES"<<endl;
for(int i=;i<=n;i++){
if(a[i]!=){
cout<<a[i]<<" ";
}
else{
int l = z[cnt[i]].l,r = z[cnt[i]].r;
if(l< && r>n) cout<<q<<" ";
else if(l<) cout<<a[r]<<" ";
else cout<<a[l]<<" ";
}
}
}
return ;
}

之后看了下标程,用的是并查集orz...

标程的想法就比较巧妙了,首先把之前说的第二种不可行情况判断一下,然后开始骚操作。

其基本思想为:值从大到小进行区间修改的操作,对于当前位置的数而言,用并查集来维护i之后小于或等于它的第一个位置

因为我们是从大到小开始涂色,对于第一次涂色,肯定能找到第一个小于或等于它的位置;对于第i次涂色,假设当前位置为pos,如果pos+1的值比pos的值大,那么它之前已经操作过了,说明已经用并查集处理过了,那么f(pos+1)就是比pos+1的值小的第一个位置;如果此时找到的值还比pos的值大,那么就继续寻找;如果比pos的值小,那么就不可行。

注意上面查找值时要满足值的存在区间范围,并且为了输出方案,我们还要对区间进行修改,这时只用对0进行修改就好了~比它大的都不用管。

具体代码如下:

#include <bits/stdc++.h>
using namespace std; const int N =2e5+;
int n,q;
int f[N],l[N],r[N];
int a[N]; int find(int x){
return f[x]==x ? f[x] : f[x]=find(f[x]);
} int main(){
cin>>n>>q;
for(int i=;i<=q;i++) l[i]=n+,r[i]=;
for(int i=;i<=n+;i++) f[i]=i;
for(int i=;i<=n;i++){
scanf("%d",&a[i]);
l[a[i]]=min(l[a[i]],i);
r[a[i]]=max(r[a[i]],i);
}
if(l[q]>r[q]){
if(l[]>r[]){
cout<<"NO";
return ;
}
a[l[]]=q;
f[l[]]=l[]+;
}
for(int i=q;i>=;i--){
for(int j=find(l[i]);j<=r[i];j=find(j)){
if(a[j] && a[j]<i){
cout<<"NO";
return ;
}
a[j]=i;
f[j]=find(j+);
}
}
puts("YES");
for(int i=;i<=n;i++) printf("%d ",a[i]?a[i]:);
return ;
}

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

  1. Codeforces Round #504 D. Array Restoration

    Codeforces Round #504 D. Array Restoration 题目描述:有一个长度为\(n\)的序列\(a\),有\(q\)次操作,第\(i\)次选择一个区间,将区间里的数全部 ...

  2. Codeforces Round #504 E. Down or Right

    Codeforces Round #504 E. Down or Right 题目描述:交互题. 有一个\(n \times n\)的方阵,有一些格子是障碍,从\((1, 1)\)出发,只能向右向下走 ...

  3. Codeforces 1023 A.Single Wildcard Pattern Matching-匹配字符 (Codeforces Round #504 (rated, Div. 1 + Div. 2, based on VK Cup 2018 Fi)

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

  4. Codeforces 1023 D.Array Restoration-RMQ(ST)区间查询最值 (Codeforces Round #504 (rated, Div. 1 + Div. 2, based on VK Cup 2018 Fi)

    D. Array Restoration 这题想一下就会发现是只要两个相同的数之间没有比它小的就可以,就是保存一下数第一次出现和最后一次出现的位置,然后查询一下这个区间就可以,如果有0的话就进行填充. ...

  5. [Educational Codeforces Round 63 ] D. Beautiful Array (思维+DP)

    Educational Codeforces Round 63 (Rated for Div. 2) D. Beautiful Array time limit per test 2 seconds ...

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

    我们知道不满足的肯定是两边大中间小的,这样就用RMQ查询两个相同等值的区间内部最小值即可,注意边界条件 #include<bits/stdc++.h> #define x first #d ...

  7. Educational Codeforces Round 11 A. Co-prime Array 水题

    A. Co-prime Array 题目连接: http://www.codeforces.com/contest/660/problem/A Description You are given an ...

  8. Educational Codeforces Round 23 D. Imbalanced Array 单调栈

    D. Imbalanced Array time limit per test 2 seconds memory limit per test 256 megabytes input standard ...

  9. Educational Codeforces Round 11——A. Co-prime Array(map+vector)

    A. Co-prime Array time limit per test 1 second memory limit per test 256 megabytes input standard in ...

随机推荐

  1. Pagehelper介绍

    本文引自:https://my.oschina.net/zudajun/blog/745232 摘要: com.github.pagehelper.PageHelper是一款好用的开源免费的Mybat ...

  2. TA-LIB】之MACD

    移动平滑异同平均线(Moving Average Convergence Divergence,简称MACD指标)策略.MACD是查拉尔·阿佩尔(Geral Appel)于1979年提出的,由一快及一 ...

  3. 初试PHP连接sql server

    最开始想使用 pdo_sqlsrv 拓展,但是一直没成功,本文采用的是 pdo_dblib + freetds. 环境:CentOS 6.8.PHP 5.6.20 freetds wget ftp:/ ...

  4. arm-none-linux-gnueabi-gcc No such file or directory这个错误的解决方法

    这个gcc可执行文件是32位的版本,而在64位系统上需要安装32位兼容包才可以运行正常 .用file命令查看这个文件得到: 解决办法: 安装ia32-libs sudo apt-get install ...

  5. Flask初学者:蓝图Blueprint

    蓝图这个名字好像就是根据单词Blueprint字面意思来,跟平常我们理解的蓝图完全挂不上钩,这里蓝图就是指Blueprint. 使用蓝图的好处是可以将不同功能作用的视图函数/类视图放到不同的模块中,可 ...

  6. WPF Datagrid对鼠标单击进行响应,借助EventSetter

    在做的一个c#的项目中发现Datagrid没办法直接对鼠标单击进行响应, 调用MouseDown事件也需要点击某一行第二次才能响应. 所以借助EventSetter来简单的实现了一个. 界面部分的代码 ...

  7. 全方位认识HDMI接口技术

    HDMI接口并不是一个开放的标准.制造商必须向HDMI标准制定协会支付版税,来换取一个生产许可证.不过这个版税可不便宜,每年要交纳15000美元的许可费,并且更黑的是每生产一个HDMI接口就要支付0. ...

  8. 2286: [Sdoi2011]消耗战

    2286: [Sdoi2011]消耗战 链接 分析 虚树练习题. 构建虚树,在虚树上DP. 跟着gxb学虚-tree... 代码 #include <cstdio> #include &l ...

  9. 剑指Offer - 九度1385 - 重建二叉树

    剑指Offer - 九度1385 - 重建二叉树2013-11-23 23:53 题目描述: 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的 ...

  10. 剑指Offer - 九度1283 - 第一个只出现一次的字符

    剑指Offer - 九度1283 - 第一个只出现一次的字符2013-11-21 21:13 题目描述: 在一个字符串(1<=字符串长度<=10000,全部由大写字母组成)中找到第一个只出 ...