SGU 142.Keyword

时间限制:0.5s

空间限制:16M

题意

      给出一个仅由'a',‘b’组成的字符串S,长度小于500 000,求一个由‘a’,‘b’组成的不是S子串的字符串T。

      输出T的长度和T。

 

Sample Input

11
aabaaabbbab

Sample Output

4
aaaa

 

 

 


 

Solution:

             从字符串长度上看,我们需要一个O(n)的算法.

             考虑串T的最大长度,在什么范围

             长度为k的串,有2k个,占了k*2k位,即1*2+2*2k,+....+p*2P<=500 000;

             可知串T的长度是小于log2(500000)<19,的.

             因此只要从S串的开始,每一位往后最多枚举19位,就能筛选出所有有用的子串.

             如果用 1 0 分别代表'a','b' ;

             那么可以用一个二进制长为19位的数代表这个串.

             只需要开一个f[length][key]的数组(length<=19,key<=219),注意到内存只有16M,因此,这个二维数组的类型必须是bool型,不然将超出内存限制.

             最后从数组中找到最短的那个没有出现过的串,输出即可.

             时间复杂度正是O(n),满足我们的需要的.

参考代码

#include <cstdio>
#include <cmath>
char ch;
int g[1 << 19];
bool f[20][1 << 19];
int k, n, len, fid;
int main() {
	scanf ("%d", &n);
	ch = getchar();
	for (int i = 1; i <= n; i++)
		g[i] = (ch=getchar() == 'a');
	for (int i = 1; i <= n; i++) {
		k = 0;
		for (int j = 0; j <= 18; j++) {
			if (i + j <= n) {
				k = k << 1 | g[i + j];
				f[j + 1][k] = 1;
			}
			else break;
		}
	}
	for (len = 1; len <= 19; len++) {
		for (k = 0; k < (1<<len); k++)
			if (!f[len][k]) {
				fid = 1;
				break;
			}
		if (fid) break;
	}
	printf ("%d
", len);
	for (int i = len - 1; i >= 0; i--)
		printf ("%c", k & (1 << i) ? 'a' : 'b');
}

  

             

原文地址:https://www.cnblogs.com/keam37/p/3840375.html