CF1023D Array Restoration 题解
题意很简单,相当于给你了一个颜色覆盖的可能部分结果,要你判断该结果是否正确并补充完整输出。
考虑无解情况。
若整个区间中没有最大值则一定无解,因为每个颜色都一定要被涂上,不可以不涂,则最大值一定会出现在其中一个位置。如果其他颜色没有出现没关系,因为可以看作每次都涂在最大值的位置上,最后被最大值覆盖了。
如果区间没有最大值,则看区间内有没有 \(0\),如果有 \(0\) 的话,把其中一个涂成最大值即可,如果没有则一定无解。
另外一种无解的情况是存在两个相同的数中间有数比它小则一定无解,这个很好判断,可以写单调栈,我写的是稀疏表。
考虑剩下的 \(0\) 如何涂色。我们可以发现,如果两个相同的数在一起,则可以看作为一个数,正确性显然。
所以我们把所有 \(0\) 都可以涂成它旁边的数。如果是第一个数则一定可以涂成 \(1\)。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+100;
int n,m;
int a[N],s[N];
bool sg;
int f[N][30];
void ST_prework()
{
for(int i=1;i<=n;i++) f[i][0]=a[i];
int t=log(n)/log(2)+1;
for(int j=1;j<t;j++)
for(int i=1;i<=n-(1<<j)+1;i++)
f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
int ST_query(int l,int r)
{
int t=log(r-l+1)/log(2);
return min(f[l][t],f[r-(1<<t)+1][t]);
}
signed main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i];
if(a[i]==m) sg=true;
}
for(int i=1;i<=n;i++)
if(!sg && a[i]==0)
sg=true,a[i]=m;
if(!sg) return cout<<"NO"<<endl,0;//区间里面必须存在最大值
for(int i=1;i<=n;i++)
if(a[i]==0)
a[i]=max({a[i-1],a[i+1],(int)1});//直接涂色,涂成隔壁的数,如果第一个数是0就可以直接涂成1,正确性显然
for(int i=1;i<=n;i++) s[a[i]]=i;
ST_prework();
for(int i=1;i<=n;i++)
{
if(s[a[i]]==i) continue;
if(ST_query(i,s[a[i]])!=a[i]) return cout<<"NO"<<endl,0;
}
cout<<"YES"<<endl;
for(int i=1;i<=n;i++) cout<<a[i]<<" ";
return 0;
}