AGC027 E - ABBreviate
? 解题记录 ? ? Atcoder ? ? 动态规划 ? ? 构造 ?    2018-09-18 21:41:12    815    0    2

Problem Statement

There is a string s consisting of a and b. Snuke can perform the following two kinds of operation any number of times in any order:

  • Choose an occurrence of aa as a substring, and replace it with b.
  • Choose an occurrence of bb as a substring, and replace it with a.

How many strings s can be obtained by this sequence of operations? Find the count modulo 109+7.

Constraints

  • 1≤|s|≤105
  • s consists of a and b.

Input

Input is given from Standard Input in the following format:

s

Output

Print the number of strings s that can be obtained, modulo 109+7.


Sample Input 1

Copy
aaaa

Sample Output 1

Copy
6

Six strings can be obtained:

  • aaaa
  • aab
  • aba
  • baa
  • bb
  • a

Sample Input 2

Copy
aabb

Sample Output 2

Copy
5

Five strings can be obtained:

  • aabb
  • aaa
  • bbb
  • ab
  • ba

Sample Input 3

Copy
ababababa

Sample Output 3

Copy
1

Snuke cannot perform any operation.


Sample Input 4

Copy
babbabaaba

Sample Output 4

Copy
35

之前难题选讲enfris Dark♂佬就讲过这个套路结果没记住。

发现如果把a看成1,b看成2,那么操作前后串的各个位置的数字和模3是余0的。

然后呢,然后好像就不会了。

既然看结果不好办我们就看向过程。

考虑把每一个过程对应一个不同的可以被凑出的字符串。

这之前我们先想一个问题:一串字符串最后能变成一个字符的条件是什么?

首先,字符串各个位置数字的和的模数一定要和最终字符相等。

但是这样是不够的,考虑ababababab....,这样没有连续相同字符就不可能操作。

现在我们就可以这样考虑了,对于t的每个字符依次在s中划分出|t|段子串,每一个子串化简的结果和t一一对应。

那么我们考虑贪心的划分,也就是从S的开头开始每一次都能划分出来就划。

比如:abbabbaaba -> a|b|b|abb|a|aba-> abbba

这样只需要最后一段是%3余0的就可以合法,然后dp模拟这个贪心特判abababab..,这是题解和DZYO大佬给的做法qwq。

然后我发现了这个做法……至今不懂为什么,代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define For(i, a, b) for(register int i = a; i <= b; ++i)
using namespace std;
const int maxn = 2e5 + 5;
const int mod = 1e9 + 7;
char s[maxn];
int dp[maxn], sum[maxn], n, flag, trans[3] = {0, -1, -1};
 
void Add(int & a, const int &b) {
	a += b;if(a >= mod) a -= mod;
}
 
int main() {
	scanf("%s", s + 1);
	n = strlen(s + 1), dp[0] = 1;
	For(i, 1, n) sum[i] = (sum[i - 1] + (s[i] - 'a' + 1)) % 3;
	For(i, 2, n)
		if(s[i] == s[i - 1]) 
			{flag = 1; break;}
	if(!flag) return printf("1"), 0;
	int from; dp[0] = 1;
	For(i, 1, n) {
		if(!sum[i] && i < n) dp[i] = 1;
		Add(dp[i], dp[i - 1]);
		from = trans[(sum[i] + (s[i] == 'a' ? 1 : 2)) % 3];
		if(~from) Add(dp[i], dp[from]);
		trans[sum[i]] = i;
	}
	printf("%d", dp[n]);
	return 0;
}


上一篇: BZOJ4503:两个串

下一篇: CF#509 Div2 F. Ray in the tube

815 人读过
立即登录, 发表评论.
没有帐号? 立即注册
2 条评论
文档导航