Codeforces - Count Good Substrings (组合数学)

[题目传送门] http://www.codeforces.com/problemset/problem/451/D

 

[题目大意]

给你一个长度最长为100000的只含有a和b的字符串。这个字符串允许一种“压缩”,相邻的相同的字符可以被缩成一个字符。比如字符串aabb可以被缩成最简ab。

接下来如按照题目中的意思来理解比较混乱。简单的说,原来的字符串中要找到有多少个压缩后是回文的子串,还要求分是奇数长度还是偶数长度。

 

[分析]

这里很容易发现一个结论,就是压缩前如果是一个回文串,压缩后一定也是,但是压缩前如果不是,压缩后仍然可能是一个回文串。所以其实我们只要考虑压缩后的情况。

这里分成四类:

1. 原字符串中是偶数长度的,两头由a结尾的。

2. 原字符串中是偶数长度的,两头由b结尾的。

3. 原字符串中是奇数长度的,两头由a结尾的。

4. 原字符串中是奇数长度的,两头由b结尾的。

 

考虑第一类,要知道,如果仅考虑压缩后的情况,满足1条件的回文串一定长成 aba , ababa 这样。接下来证明一个结论,出现在原字符串偶数位的a,和任意一个出现在奇数位的a,配对后的字串一定回文。

简单证明:

形如a...a 的字串 一定可以缩成 ab....ba 或 aba 后者已经是一个回文,证明前者是否一定是个回文,前者一定可以压缩为 aba....aba 或 ababa 。可以一直递推下去,因为原来字符串中,前后两个a一个在奇数位,一个在偶数位,所以原字符串中的这个字串是偶数的长度。 证明结束。

其实递推到第二步时就可以发现形如ab...ba 这里的两个b也是一个在奇数位一个在偶数位,相当于证明 一个在奇数位b和一个在偶数位的b形如b....b一定回文。最后总能缩到一个程度,使其回文。

第二类同第一类。

考虑第三类,证明结论 : 任意两个奇数位a结尾的形如 a.....a 的子串一定回文。 任意两个偶数位a结尾的形如 a....a 的子串一定回文。

简单参考上面的证明:

形如a....a 的子串一定可以缩成 ab....ba 或 aba , 后者已经回文。 前者可以不停递推到回文。

由于原来字符串中,两个结尾的a要么都是奇数位要么都是偶数位,所以原来字符串中的长度一定是奇数。

第四类同第三类。

另外单独一个字符都是奇数回文,所以再加上字符串的长度。

[代码君]

 1 #include <iostream>
 2 #include <string>
 3 using namespace std;
 4 string in;
 5 int main(){
 6     cin >> in;
 7     long long a0 = 0 , a1 = 0;
 8     long long b0 = 0 , b1 = 0;
 9     int len = in.size();
10     for (int i = 0; i < len; i++) {
11         if (i % 2) {
12             in[i] == 'a' ? a1++ : b1++;
13         }
14         else in[i] == 'a' ? a0++ : b0++;
15     }
16     long long ans1 = a0 * a1 + b0 * b1;
17     long long ans2 = (a0 * (a0 - 1) / 2) + (a1 * (a1 - 1) / 2) + (b0 * (b0 - 1) / 2) + (b1 * (b1 - 1) / 2) + len;
18     cout << ans1 << " " << ans2 << endl;
19     return 0;
20 }

 

posted @ 2016-05-24 14:51  ACMZZ  阅读(167)  评论(0编辑  收藏  举报