ARC153C ± Increasing Sequence
由于个人偏好原因,以下将用
题目大意
-
给定
n 和一个长度为n 的序列a ,满足a_i \in \{-1,+1\} 。 -
你要尝试求出一个长度为
n 的序列b ,满足以下限制:-
-
序列严格递增,即
\forall 1 \leq i < n ,b_i < b_{i+1} ; -
将
a 中的正负号带入b 中后,b 的和为0 ,即\sum\limits_{i=1}^n{a_ib_i} = 0 。
-
-
如果存在这样的序列,输出
Yes和一个满足条件的序列b ;如果不存在,则输出No。 -
题解
记
发现样例 1 的输出没有规律,由于题目要求
由于填入的数两两相邻,无法直接修改
于是可以得出结论:如果
等等,会不会只改一个数超出数值大小限制了?是否会有把调整分摊到两个数的需要?
一方面,即使在
另一方面,这也引出了另一个突破口:在调整了
以前缀为例,对于
在这里,
那怎么控制改变的数值大小呢?以
(如果还不清楚做法可以结合后面的代码理解)
说了这么多,让我们来手模一组数据吧:
一开始填入
显然,如果通过调整同时能使
考虑一个以
-
记
\{\underbrace{-1, \dots, -1}_{x\text{个}-1},\underbrace{+1, \dots, +1}_{x\text{个}+1}\} 为U ; -
-
-
-
最后发现符合要求的
a 只能是形如若干个U (x 不一定相等)拼接而成。
证明不够严谨,但可以感性理解这个结论。我不会写啊QwQ
构造是构造出来了,可惜这样的序列本身就是无解的。由于这样的
开头是
至此可知,如果不是同时能使
到这里我们终于可以说:初始设置的
关于时间复杂度:填入
代码
#include<cstdio>
#define ll long long
#define N_ 200010
int n,sgn[N_];
int pre_n1,pre_p1,suf_n1,suf_p1;
//(前/后缀)_(d_a)
//pre(fix), suf(fix)
//n(egative)1, p(ositive)1
ll ans[N_],s;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&sgn[i]);
ans[i]=i,s+=sgn[i]*i;
}
for(int i=1,cnt=0;i<=n;i++){
cnt+=sgn[i];
//由于变化量为 ±1,cnt 第一次变为正/负时绝对值一定为 1
if(!pre_n1&&cnt<0)pre_n1=i;
if(!pre_p1&&cnt>0)pre_p1=i;
if(pre_n1&&pre_p1)break;
}
for(int i=n,cnt=0;i;i--){
cnt+=sgn[i];
if(!suf_n1&&cnt<0)suf_n1=i;
if(!suf_p1&&cnt>0)suf_p1=i;
if(suf_n1&&suf_p1)break;
}
int pre=0,suf=0;
//根据 s 的正负性选择需要的区间
if(s<0)s=-s,pre=pre_n1,suf=suf_p1;
else if(s>0)pre=pre_p1,suf=suf_n1;
if(s){
if(pre){
for(int i=1;i<=pre;i++)ans[i]-=s;
}
else if(suf){
for(int i=suf;i<=n;i++)ans[i]+=s;
}
else{
printf("No"); return 0;
}
}
printf("Yes\n");
for(int i=1;i<=n;i++){
printf("%lld ",ans[i]);
}
return 0;
}