[AtCoder] AT4379 [AGC027E] ABBreviate

Description

\(Link\)

Solution

\(G(S)=\sum\limits_{i=1}^{|S|}(S_i-'a'+1)\pmod{3}\)。那么经过若干次变换,\(G(S)\)始终不会改变。

注意到一个字符串\(S\)能变换成\(T\)\(S\neq{T}\)),当且仅当\(S\)能被划分成若干段,满足每一段的\(G(S')\)都等于\(G(T_i)\)\(S\)中至少有两个连续字符相同,且若还剩下最后一段没有匹配,则\(G(S_{lst})=0\)。(因为\(G(S)=G(T)\)

举个例子:设\(S=aabbabaabaaabab\)\(T=abba\),那么\(S\)会被划分为\(a|abb|abaa|baa|abab\)。这是满足的,因为\(G(abab)=0\)

因此,我们设\(dp[i]\)表示在\(S\)中,以\(S_i\)为后缀的答案。

最开始先把形如\(ababababababa\)的判掉。

再设一个\(nxt[i][0/1]\)表示\(dp[i]\)由哪里更新而来(如由\(dp[nxt[i][0]]\)再向前面添一个\(a\)得来)

那么转移方程即为\(dp[i] = dp[nxt[i][0]] + dp[nxt[i][1]] + (s == 0)\),其中\(s\)表示\(G(S_{i\sim{n}})\)

解释:可以由\(dp[nxt[i][0]]\)再向前面添一个\(a\)得来,也可以由\(dp[nxt[i][1]]\)再向前面添一个\(b\)得来,还可以直接作为一个后缀(这要满足\(G(S_{i\sim{n}})=0\)

\(nxt\)数组的更新如下:

\(nxt[i][0]\)为例:如果\(S_i=a\),那么\(nxt[i][0]=i+1\);如果\(S_i=S_{i+1}=b\),那么\(nxt[i][0]=i+2\);(\(bb\rightarrow{a}\)),否则\(nxt[i][0]=nxt[i+2][0]\)。例如,在\(S=babba,i=1\)时,计算可得\(nxt[i][0]=5\)。发现\(babb\)恰好可以转化为\(a\)

答案为\(dp[1]\)。当然,要记得最后减掉\(s==0\),因为整个串不可能单独做一个后缀。

Code

#include <bits/stdc++.h>

using namespace std;

const int mod = 1e9 + 7;

int n, s, dp[100005], nxt[100005][2];

char ch[100005];

int read()
{
	int x = 0, fl = 1; char ch = getchar();
	while (ch < '0' || ch > '9') { if (ch == '-') fl = -1; ch = getchar();}
	while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + ch - '0'; ch = getchar();}
	return x * fl;
}

int main()
{
	scanf("%s", ch + 1);
	n = strlen(ch + 1);
	int ok = 0;
	for (int i = 1; i <= n - 1; i ++ )
		if (ch[i] == ch[i + 1])
			ok = 1;
	if (!ok)
	{
		puts("1");
		return 0;
	}
	dp[n + 1] = 1;
	nxt[n + 1][0] = nxt[n + 1][1] = n + 2;
	nxt[n + 2][0] = nxt[n + 2][1] = n + 2;
	for (int i = n; i >= 1; i -- )
	{
		s = (s + ((ch[i] == 'a') ? 1 : 2)) % 3;
		if (ch[i] == 'a') nxt[i][0] = i + 1;
		else if (ch[i + 1] == 'b') nxt[i][0] = i + 2;
		else nxt[i][0] = nxt[i + 2][0];
		if (ch[i] == 'b') nxt[i][1] = i + 1;
		else if (ch[i + 1] == 'a') nxt[i][1] = i + 2;
		else nxt[i][1] = nxt[i + 2][1];
		dp[i] = (dp[nxt[i][0]] + dp[nxt[i][1]] + (s == 0)) % mod;
	}
	printf("%d\n", (dp[1] - (s == 0) + mod) % mod);
	return 0;
}
posted @ 2021-03-01 21:07  andysj  阅读(78)  评论(0编辑  收藏  举报