FZU 2218 Simple String Problem(简单字符串问题)
Description |
题目描述 |
Recently, you have found your interest in string theory. Here is an interesting question about strings. You are given a string S of length n consisting of the first k lowercase letters. You are required to find two non-empty substrings (note that substrings must be consecutive) of S, such that the two substrings don't share any same letter. Here comes the question, what is the maximum product of the two substring lengths? |
最近,你突然迷上了字串论。下面是一个关于字符串的有趣问题。 给定一个字符串S,长度为n且包含前k个小写字母。 你被要求从S中找出两个非空子串(注意,子串必须是连续的),并且两个子串不共享任何字母。问题来了,两个子串长度乘积的最大值是多少? |
Input |
输入 |
The first line contains an integer T, meaning the number of the cases. 1 <= T <= 50. For each test case, the first line consists of two integers n and k. (1 <= n <= 2000, 1 <= k <= 16). The second line is a string of length n, consisting only the first k lowercase letters in the alphabet. For example, when k = 3, it consists of a, b, and c. |
输入的首行是一个整数T,表示测试样例的数量。1 <= T <= 50。 对于每个测试样例,第一行有2个整数n和k。(1 <= n <= 2000, 1 <= k <= 16)。 第二行有有一个长度为n的字符串,仅由字母表前k个小写字母组成。比如,k=3,组成元素为a,b,和c。 |
Output |
输出 |
For each test case, output the answer of the question. |
对于每个测试样例,输出问题的答案。 |
Sample Input - 输入样例 |
Sample Output - 输出样例 |
4 25 5 abcdeabcdeabcdeabcdeabcde 25 5 aaaaabbbbbcccccdddddeeeee 25 5 adcbadcbedbadedcbacbcadbc 3 2 aaa |
6 150 21 0 |
Hint |
提示 |
One possible option for the two chosen substrings for the first sample is "abc" and "de". The two chosen substrings for the third sample are "ded" and "cbacbca". In the fourth sample, we can't choose such two non-empty substrings, so the answer is 0. |
对于第一个例子,其中一种可行的子串选择方案为"abc"和"de"。 第三个例子选择的子串为"ded"和"cbacbca"。 第四个例子中,我们无法找出两个非空子串,所以答案为0。 |
【题解】
解题思路:枚举,贪心/搜索,状态压缩/转移。
代码构架:枚举,状态压缩/转移,贪心。
枚举:
因为最多只有前16个字母,一共216种状态,可以使用二进制压缩成一个int来记录每种字母出现的状态(当然你要用unsigned short我也不栏你_(:3 」∠)_,不过int明显看着舒服敲着方便。某人:你再说就要离题了啊,喂!)
枚举的时候可以指定开头再叠加状态,也可以按01背包来写,记录下每种状态子串长度的最大值。
贪心/搜索:
假如我们现在选了0001状态的子串,那么秉持着不拿人民一针一线(误)的优(hen)良(tai)作风,只要最后面不是1的我都要了!
因此得到在可选情况下最好的状态1110。
那么问题来了,学挖掘机……哦不,1110的字符串长度可能是0啊,我们要找的可能是1100,1010,***0。那么把***0中的最大长度丢到1110中,就可以得到1110(其实是***0)的最大长度。
使用位运算可以很方便地完成比较。
状态压缩/转移:
大道无言,百态汇流。
【代码 C++】
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 int n, k, bag[1 << 16], bit[17]; 5 int fid(){ 6 memset(bag, 0, sizeof(bag)); 7 char data[2005]; 8 gets(data); 9 int i, len, temp, ed; 10 for (i = 0; i < n; i += 2){//枚举 11 --i; 12 for (len = 1, temp = 0; i + len < n; ++len){ 13 temp |= bit[data[i + len] - 'a']; 14 bag[temp] = std::max(bag[temp], len); 15 } 16 } 17 for (i = 1, ed = bit[k]; i < ed; ++i){//压缩状态 18 for (temp = 0; temp <= k; ++temp){ 19 if (i & bit[temp]) bag[i] = std::max(bag[i], bag[i^bit[temp]]); 20 } 21 } 22 for (i = 1, len = 0, --ed; i < ed; ++i){//搜索 23 len = std::max(len, bag[i] * bag[i^ed]); 24 } 25 return len; 26 } 27 int main(){ 28 for (int i = 0, j = 1; i < 17; ++i, j <<= 1) bit[i] = j; 29 int T; 30 scanf("%d", &T); 31 while (T--){ 32 scanf("%d%d", &n, &k), getchar(); 33 printf("%d\n", fid()); 34 } 35 return 0; 36 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<cstring> 3 short bag[65536]; 4 int n, k, letter[17]; 5 int fid(){ 6 memset(bag, 0, 131072); 7 char data[2005]; 8 gets(data); 9 int i, len, temp, ed = 1 << k; 10 --ed; 11 for (i = 0; i < n; i += 2){ 12 --i; 13 for (len = 1, temp = 0; i + len < n && temp^ed; ++len){ 14 temp |= letter[data[i + len] - 'a']; 15 if (bag[temp] < len) bag[temp] = len; 16 } 17 } 18 for (i = 1; i <= ed; ++i){ 19 for (temp = 0; temp <= k; ++temp) 20 if (i & letter[temp] && bag[i] < bag[i^letter[temp]]) 21 bag[i] = bag[i^letter[temp]]; 22 } 23 for (i = 1, len = 0; i < ed; ++i){ 24 temp = bag[i] * bag[i^ed]; 25 if (len < temp) len = temp; 26 } 27 return len; 28 } 29 int main(){ 30 for (n = 0, k = 1; n < 17; ++n, k <<= 1) letter[n] = k; 31 int T; 32 scanf("%d", &T); 33 while (T--){ 34 scanf("%d%d", &n, &k), getchar(); 35 printf("%d\n", fid()); 36 } 37 return 0; 38 }
FZU 2218