AT agc027E - ABBreviate

题目链接

大概就是寻找不变量,发现若把 \(\texttt a\) 看成 \(1\)\(\texttt b\) 看成 \(2\),则总和 \(\bmod 3\) 的值不变。

然后考虑对这些 \(1\)\(2\) 的前缀和数组 \(a\)(下标 \(0 \sim n\))进行操作,发现等价于每次删掉一个数,要求其两边的数不同。

接着可以推出把一个长度 \(> 0\) 的区间 \([l, r]\) 删空的条件有

  1. \(a _ l \neq a _ r\)

  2. \([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;
}
posted @ 2026-01-19 19:32  yemuzhe  阅读(1)  评论(0)    收藏  举报