[??记录]AT2340 [AGC011D] Half Reflector
command_block
2021-04-28 11:50:47
**题意** : 有一排 $n$ 个机器,每个机器为两种状态之一 :
- $\rm A$ : 反弹滚过来的球。
- $\rm B$ : 允许球通过。
每与球互动一次,机器的状态就会改变。
现在从左侧投入一个球,等待直到球从左侧或者右侧离开。可以证明球一定会离开。
重复投 $k$ 次,问最终机器的状态。
$n\leq 2\times 10^5,k\leq 10^9$ ,时限$\texttt{2s}$。
------------
好毒啊,脑补要累死啦……写个暴力观察一下规律。
可以发现,从左侧投入一个球时,机器的改变分为两种情况 :
- 最左侧是 $A$ : 最左侧变为 $B$。
- 最左侧不是 $A$ :整个序列取反后,向左循环移位一次。
不难写出一个 $O(k)$ 的模拟。
继续观察规律,当不断投球时, 形如 `...BABA` 的后缀不会被改变。
最终会稳定在 `BABABA` 或者 `xBABA` (第一位反复横跳)
而且,每投至多两次球,必然会在后方多产生一组 `BA`。
所以我们只需模拟 $2n$ 轮,之后的行为是容易预测的。
```cpp
#include<algorithm>
#include<cstdio>
#define MaxN 200500
using namespace std;
int n,k;
char s[MaxN];
int main()
{
scanf("%d%d%s",&n,&k,s+1);
for (int i=1;i<=n;i++)s[i]-='A';
if (n&1)k=min(k,2*n+(k&1));
else k=min(k,2*n);
int p=1,fl=0;
while(k--){
if (s[p]^fl){
p=p%n+1;
fl^=1;
}else s[p]=fl^1;
}for (int i=1;i<=n;i++)s[i]=(s[i]^fl)+'A';
for (int i=p;i<=n;i++)putchar(s[i]);
for (int i=1;i<p;i++)putchar(s[i]);
return 0;
}
```