分析
序列操作题,先模拟数据,想到规律,看到这个过程是可逆的。
于是可以转化为将a删去一个0,前面取反,看能不能变成空串。
这样之后无解的情况呼之欲出了,就是最后一个是1的时候,无论如何都无法被删去。
那为什么最后一个是0就一定有解呢?可以想到,删去最后一个取反之后,最后一个也必须是0,那么最后的结构一定是“1 0”,如果是“0 0”,就删去倒数第二个0,不管倒数第二个是什么,操作后都保证最后一个是0,这样子每次必定删去一个数,有限次数内必有解。
上述证明过程也就是构造方案了,只需要把操作顺序存起来倒着输出就行。细节:别真的一个个取反用个bool记录就行。
第二种思路:
升华
本题是构造题。首先要能发现什么情况无解,其次要能想到让每次操作影响的范围尽可能小。
上代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int t,n,a[100010],tot,b[100010];
int main()
{
cin>>t;
while(t--)
{
bool rev=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
if(a[n]==1)
{
cout<<"NO"<<endl;
continue;
}
cout<<"YES"<<endl;
while(n>0)
{
if(n==1) b[++tot]=0;
else if(a[n-1]^rev!=0)
{
b[++tot]=n-1;
rev^=1;
}
else
{
b[++tot]=n-1-1;
rev^=1;
}
n--;
}
for(int i=tot;i>=1;i--) cout<<b[i]<<' ';
cout<<endl;
memset(b,0,sizeof(b));
tot=0;
}
return 0;
}