CF 1023D. Array Restoration(构造模拟)

Linking


大意:

给定一个长度为 n 的序列。
现在有 q 次操作,对于第 i 次:选定长度不为 0 的一段区间,把区间中的所有值变为 i。
现在对于给定的序列,判断是否由上述 q 次操作得到。
序列中可能有 0,0 可以变成 1~q 中的任意数。

思路:

注意几个点:

  1. 不存在中间的元素比两端的小(除去0): 单调栈,维护单调递增的栈。
    遍历每个位置,如果该元素之前出现过,判断第一个小于等于该元素的值是不是和其相等。 如果不是,说明中间有比其小的,NO。

  2. 元素的最大值一定要为 q:
    把一个 0 变为 q。如果没有 0,NO。

  3. 最后把 0 都变成相邻元素:
    正着走,反着走,把 0 变为相邻元素。特判全为 0 情况。

Code:

const int N = 200010, mod = 1e9+7;
int T, n, m;
int a[N], b[N];

int main(){
	Ios;
	
	cin>>n>>m;
	
	int flag=0, maxa=0;
	for(int i=1;i<=n;i++) cin>>a[i];

	stack<int> stk; //判断是否有中间比两端小的情况 
	for(int i=1;i<=n;i++)
	{
		if(a[i]==0) continue;
		
		while(stk.size() && stk.top() > a[i]) stk.pop();
		
		if(b[a[i]] && stk.top()!=a[i]){
			cout<<"NO";return 0;
		}
		
		stk.push(a[i]);
		
		b[a[i]]++;
	}
	
	for(int i=1;i<=n;i++) maxa=max(maxa,a[i]); //找到最大值 
	
	if(maxa==m) //最大值是m,把0都变成相邻的 
	{
		for(int i=1;i<=n;i++)
			if(a[i]==0) a[i]=a[i-1];
		
		for(int i=n;i>=1;i--){
			if(a[i]==0) a[i]=a[i+1];
		}
		
		for(int i=1;i<=n;i++) if(a[i]==0) a[i]=m;
		
		cout<<"YES\n";
		for(int i=1;i<=n;i++) cout<<a[i]<<" ";
	}
	else //最大值不是m,要让其中的一个0变为m,其余的变成相邻的 
	{
		int flag=0;
		for(int i=1;i<=n;i++)
		{
			if(a[i]==0 && !flag) flag=1, a[i]=m;
			else if(a[i]==0) a[i]=a[i-1];
		}
		if(!flag){ //最大值不是m,还不存在0,无解 
			cout<<"NO";return 0;
		}
		
		for(int i=n;i>=1;i--) 
			if(a[i]==0) a[i]=a[i+1];
		
		for(int i=1;i<=n;i++) if(a[i]==0) a[i]=m;
		
		cout<<"YES\n";
		for(int i=1;i<=n;i++) cout<<a[i]<<" ";
	}
	
	return 0;
}

改了好久,发现判断中间比两端小的情况判断错了,比两端大的也判断了。。
改掉之后,超时。
最后改成单调栈O(n)判断过了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值