Solution
将’a’看成
1
1
1,’b‘看成
2
2
2。那么无论怎么变化,总和对于
3
3
3的余数不变。
同时我们可以得到一个结论,对于一段
[
l
,
r
]
[l , r]
[l,r],如果最后这一段变成了某个字母,那么一定满足:
- 总和膜 3 3 3相等。
- 至少有一对连续相等或者长度为一。
那么有了这个结论,考虑如何计算。对于一个
t
t
t。首先其模
3
3
3余数与
s
s
s相同。我们每次一位一位匹配。每次贪心的向后找,直到能够凑成要凑的字母。这时候要注意,最后
s
s
s可能还剩下一部分,由于要求同于,所以要保证剩下部分模
3
3
3为
0
0
0即可。这样可行的话,那么
t
t
t就是可以变成的。
从而我们设
f
[
n
]
f[n]
f[n]表示这样贪心时
n
n
n能够有多少种分法,每次贪心找一段即可。最后答案就是枚举剩下部分有多长。
code
如果任然不懂可以参见下面代码中的注释。
#include <bits/stdc++.h>
#define MOD 1000000007
#define INF 1061109567
#define bp __builtin_popcountll
#define pb push_back
#define in(s) freopen(s,"r",stdin);
#define out(s) freopen(s,"w",stdout);
#define fi first
#define se second
#define bw(i,r,l) for (int i=r-1;i>=l;i--)
#define fw(i,l,r) for (int i=l;i<r;i++)
#define fa(i,x) for (auto i:x)
using namespace std;
const int N = 1e5 + 5;
string s;
int n, dp[N], f[N][3], sum[N];
bool bad = 1;
void add(int &x, int y) {
x += y;
if (x >= MOD) x -= MOD;
}
signed main() {
#ifdef BLU
in("blu.inp");
#endif
ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> s;
int n = s.length();
/*
We can see greedily that always picking the earliest possible spots to create an a or b is good
enough.
dp[i]: Number of different substrings we can create from the first i characters of s
Then pass onto 2 positions j1 and j2, so that i + 1 -> j1 can create 'a', and to j2 create 'b'.
For a, psum[j1] - psum[i] must mod 3 remainder 1. So we can know the remainder psum[j1] should
have, and this can be easily found by a supporting array.
*/
s = " " + s;
memset(sum, 0, sizeof sum);
fw (i, 1, n + 1) sum[i] = sum[i - 1] + (s[i] == 'a' ? 1 : 2);
memset(f, -1, sizeof f);
/*
f[i][j]: The first index k that considering the segment from i + 1 -> k, its sum MOD 3 is equal to
j. Also, there are at least 2 adjancent characters that are equal (or the length is 1)
*/
fw (i, 1, n) if (s[i] == s[i + 1]) bad = 0;
if (bad) {
cout << "1";
return 0;
}
bw (i, n + 1, 0) {
fw (j, 0, 3) f[i][j] = f[i + 1][j];
if (i) f[i][sum[i] % 3] = i;
}
memset(dp, 0, sizeof dp);
dp[0] = 1;
fw (i, 0, n + 1) {
fw (j, 1, 3) {
int k = (j + sum[i]) % 3;
k = f[i][k];
if (k != -1) {
add(dp[k], dp[i]);
bool flag = k == i + 1;
for (int d = i + 2;d <= k;d++){
if (s[d] == s[d-1]) flag |= 1;
}
assert(flag);
}
}
}
int ans = 0;
fw (i, 1, n + 1) {
if ( (sum[n] - sum[i]) % 3 == 0) add(ans , dp[i]);
printf("%d\n",dp[i]);
}
cout << ans;
return 0;
}