[CF286C] Main Sequence

问题描述

定义幸运数列:

空数列是幸运数列

如果 S 是幸运数列,那么 {r, S, -r} 也是幸运数列 (r > 0)

如果 S 和 T 都是幸运数列,那么 {S, T} 也是幸运数列

给定一个幸运数列中每个数的绝对值,并且要求其中的一些数是负数,其他的可正可负。

问是否有合法方案,如果有,给出任意一种方案。 N ≤ 10^6

幸运数列例子:{1, 2, -2, -1, 1, -1, 1, -1}

输入:1 1 1 1 要求第三个数是负数 输出: 1 1 -1 -1

样例输入

2
1 1
0

样例输出

YES
1 -1

解析

可以比较容易的看出来这是一个括号序列的形式。如果将正数视为左括号,负数视为右括号,那么给定一些数为负数就说明钦定了一些右括号,需要判断是否有满足要求的左括号。为了限定右括号,我们从右往左扫一遍,如果栈顶元素不等于当前元素或当前元素被指定为负数,就将元素入栈并标记为负数;否则弹出栈顶元素。最后如果栈不为空,说明无解;否则输出答案。

代码

#include <iostream>
#include <cstdio>
#define int long long
#define N 1000002
using namespace std;
int n,m,i,a[N],q[N],s[N],top;
bool f[N];
int read()
{
	char c=getchar();
	int w=0;
	while(c<'0'||c>'9') c=getchar();
	while(c<='9'&&c>='0'){
		w=w*10+c-'0';
		c=getchar();
	}
	return w;
}
signed main()
{
	n=read();
	for(i=1;i<=n;i++) a[i]=read();
	m=read();
	for(i=1;i<=m;i++){
		q[i]=read();
		f[q[i]]=1;
	}
	for(i=n;i>=1;i--){
		if(s[top]!=a[i]||f[i]) s[++top]=a[i],f[i]=1;
		else top--;
	}
	if(top){
		puts("NO");
		return 0;
	}
	puts("YES");
	for(i=1;i<=n;i++){
		if(f[i]) printf("%lld ",-a[i]);
		else printf("%lld ",a[i]);
	}
	puts("");
	return 0;
}

反思

若将原序列视为括号序列,则给定哪些数是负数就相当于钦定了一些右括号的位置。所以从右往左会比从左往右少写很多东西。还是要注意想好之后能否简化代码的写法,否则有可能会带来非常多的麻烦。

posted @ 2019-10-26 22:35  CJlzf  阅读(197)  评论(0编辑  收藏  举报