GoodCoder666的个人博客

ARC138 B - 01 Generation 题解

2022-04-14 · 3 min read
C++ 算法竞赛

ARC138 B - 01 Generation

思路

考虑逆向思维,很容易想到可以优先从后面删掉0(操作B的逆向操作),然后如果前面是0则删掉它并将序列翻转(操作A的逆向操作),一直重复这两个步骤直到字符串为空。如果中途无法操作,输出No,否则输出Yes

下面我们来证明这个方法的正确性:

  • 首先,假设有一个序列AA按照上述方法输出No,但正确答案为Yes
  • 则一定在某一步(可能是第一步)只能先倒推操作A,而不是操作B,设这一步执行前的序列为SS
  • 此时,令N=SN=|S|,则S1=SN=0S_1=S_N=0
  • 如果先倒推操作A,得到(S2,S3,,SN1,1)(S_2,S_3,\dots,S_{N-1},1)
  • 如果先倒推操作B,得到(S1,S2,,SN1)(S_1,S_2,\dots,S_{N-1})
  • 对比两个序列,发现先倒推操作B不会影响后续倒推A的结果,因此,序列SS不存在
  • 结论:做法正确。

代码

代码实现时,没有必要真正翻转序列,只需记录当前翻转的状态(0011),记为flipped\text{flipped},则实际的Ai=AiflippedA_i=A_i'\oplus\text{flipped}(其中AiA_i'为输入的AA\oplus表示异或/XOR操作)。

删除时可以使用deque或者数组l,rl,r端点记录。

#include <cstdio>
#define maxn 200005
using namespace std;

bool a[maxn];

int main()
{
	int n = 0;
	char c;
	while((c = getchar()) != '\n')
		n = (n << 3) + (n << 1) + (c ^ 48);
	for(int i=0; i<n; i++, getchar())
		a[i] = getchar() ^ 48;
	bool flipped = false;
	for(int l=0, r=n-1; a[l]==flipped; flipped^=1, l++)
		while(!a[r] ^ flipped)
			if(l > --r)
				return puts("Yes"), 0;
	puts("No");
	return 0;
}