AtCoder Regular Contest 180

A - ABA and BAB

题意:给定一个长度为n的字符串,每次操作可以将s中连续的子串"ABA"->"A", 或者"BAB"->"B"。该操作可以执行任意的次数,但是相同的串不进行计数。 问有多少种不同的串可以通过操作得到。

思路:根据操作的特性,可以想到奇偶性相同的位数上的字符需要相等,并且中间字符需要不相等才可以进行变换。
于是我们对所有的奇(或者偶)位上的字符进行取反变换,这样只要统计连续的相同字符数量的长度,就可以知道该长度的串有多少种变换方式。
将s分为若干个块来考虑,每个块中所有的字符都相等,容易知道每个块中的变换方法数量的乘积就是最后的答案。

总结:题目的描述很容易让人想动态规划,但是感觉不对,这个状态怎么表示,怎么转移呢?如何从暴力的方法进行重复计算降低,来压缩时间呢。。感觉好像行不通。 后来看了题解一时间也不理解,然后举了一些例子以后,就可以明白了。 这种操作的特性就是容易对问题进行简化,因为奇偶性相同的位必须字符相同,奇偶性不同的位奇偶性必须不同。 所以对奇数位或者偶数位进行一个取反的变换,问题就可以转化为求字符相等的字符串长度。 这种问题的转变正确性可以保证的原理就是,只改变奇数或者偶数位上的字符,不会影响最终的计数。 还有一个容易产生的疑惑是,这种转换了问题角度以后,是怎么考虑重复的串的? 目前的理解是根据长度,对于一段连续的字符串来说,变换后的长度如果相等的话,那么就是一个相同的串。 比如ABAB,变换前面得到AB,变换后面也是AB。

constexpr int mod = (int)1e9 + 7;
void solve() {
	int n;
	cin >> n;
	
	string s;
	cin >> s;
	
	long long ans = 1;
	int len = 1;
	for (int i = 1; i < n; ++i){
		if (i & 1){
			s[i] += (s[i] == 'A' ? 1 : -1);
		}
		if (s[i] == s[i - 1]){
			len ++;
		}
		else{
			ans *= 1ll * (len + 1) / 2;
			len = 1;
			ans %= mod;
		}
	}
	
	ans *= 1ll * (len + 1) / 2;
	
	cout << ans % mod << endl;
}
posted @   _Yxc  阅读(51)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示