[ARC180A] ABA and BAB 题解

· · 题解

思路

容易发现,如果我们能把原串分解成互不干扰的部分,那么,我们就可以用乘法原理求解。

什么部分是干扰的?什么部分是不干扰的?

ABABAB 就是互相干扰的部分 ,因为拼接后的 ABABAB 的方案数比分别计算 ABABAB 的方案数再相乘不同,可以自己手动尝试一下。

容易发现,我们可以将连续的 AB 串分为一个部分,证明如下(并不严谨):

如果我们不能将连续的 AB 串分为一个部分,那么有两种可能:

如果把这个子串变成是单独的一部分,会有如下情况(这里的原串指上面的连续 AB 串):

通过最终的不断合并,终究会合并成原串。

所以,这个串的其中一个子串不会被两个部分分解。

第二种可能

我们刚才一直在说 干扰 ,意思似乎手造一造就懂了,但是在这里不行,我们需要 更严谨 的定义。

什么串是互相干扰的?通过刚才讲解的第一种可能,我们发现,互相干扰的串满足一种性质:

我们发现,如果这两个串拼接后,是一个连续的 AB 串,那么,你不管是对左边还是对右边做操作,都一样。

为什么哪?

观察替换:

这不就是删除一个 AB 串吗?

那么,一个连续的 AB 串对左边或对右边做操作,就都等价于删掉一个 AB 串。

由于连续 AB 串是由若干个 AB 串加某些字符组成,做出以下分类讨论:

这里的顺序仅仅是指 AB 串与多余字符之间的位置关系。

刚刚我们说了,如果这两个串拼接后,是一个连续的 AB 串,那么,你不管是对左边还是对右边做操作,都一样。

所以,如果这两个串拼接后是一个连续的 AB 串,它们互相干扰,反之不干扰(这里我就不证明了,可以按照我的方法试着证明)。

如果这两个串拼接后是一个连续的 AB 串,那么,我们找的连续 AB 串不应该是这个,这是不可能的。

所以,这个串和与它相邻的串是不互相干扰的。

综上所述,我们可以将连续的 AB 串分为一个部分。

那么,剩下的就是一个问题了:

容易发现,每次操作都是删除一个 AB 串,好像是 \lfloor\frac{|s|}{2}\rfloor+1,但是变形终究是变形,形变意不变,当 |s|\bmod 2=0 时,是没有空串的,没有 +1

但是 |s|\bmod 2=1 时,有 +1

怎么办?

很简单,变成 \lceil\frac{|s|}{2}\rceil 就行了。

为了编码简便,可以变成 \lfloor\frac{|s|+1}{2}\rfloor

代码

代码 30 行,蕴含着我们的人类智慧!

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e9+7;
int n;
string s;
string t;
int ans=1;
int cal(string t){
    //cal蕴含着我们的人类智慧(cal的可行性,什么条件下使用cal,cal的计算过程)
    return (t.size()+1)/2;
}
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin>>n;
    cin>>s;
    for(int i=0;i<n;i++){
        if(t!=""&&t[t.size()-1]==s[i]){//不是连续AB串了 
            ans=(ans*cal(t))%mod;//乘法原理 
            t="";
        }
        t+=s[i];
    }
    ans=(ans*cal(t))%mod;//最后可能还有剩余 
    cout<<ans;
    return 0;
}