题目链接
大概就是寻找不变量,发现若把 \(\texttt a\) 看成 \(1\),\(\texttt b\) 看成 \(2\),则总和 \(\bmod 3\) 的值不变。
然后考虑对这些 \(1\) 和 \(2\) 的前缀和数组 \(a\)(下标 \(0 \sim n\))进行操作,发现等价于每次删掉一个数,要求其两边的数不同。
接着可以推出把一个长度 \(> 0\) 的区间 \([l, r]\) 删空的条件有
-
\(a _ l \neq a _ r\)
-
\([l - 1, r + 1]\) 中至少包含 \(3\) 种数。
现在可以把题目转化成选择 \(a\) 的本质不同合法子序列,且必须选 \(0\) 和 \(n\) 的方案数。
这可以类似本质不同子序列,设计一个 dp(形似被动转移的 dp 套 dp),\(f _ i\) 能从 \(f _ j\) 转移过来当且仅当对于 \(a _ j\) 相同的所有位置中,\(j\) 是最大的使得开区间 \((j, i)\) 能被删空的位置,答案就是 \(f _ n\)。
初值怎么赋?dp 套 dp 的思想只是最大化子序列开头位置,但我们的要求是 \(0\) 必须选。但我们有惊人的结论:若 \(a\) 中存在 \(3\) 种数,则对于任意 \(a _ i \neq 0\),\(f _ i\) 初值为 \(1\);否则答案为 \(1\)。这可以通过调整法证明,如下图:

#include<cstdio>
#include<cstring>
#define N 100005
using namespace std;const int mod=1e9+7;
int n,a[N],f[N],las[3],las2[3][3];
char s[N];
int main() {scanf("%s",s+1),n=strlen(s+1);for(int i=1;i<=n;i++) a[i]=(a[i-1]+(s[i]=='a'?1:2))%3;for(int i=1;i<=n;i++) {f[i]=((a[i]!=0)+f[i-1]+f[las2[3-a[i]-a[i-1]][a[i-1]]])%mod;las[a[i]]=i;for(int j=0;j<3;j++) if(j!=a[i]) las2[j][a[i]]=las[j];}printf("%d\n",las[1]&&las[2]?f[n]:1);return 0;
}