问题 D:白狼
这个题很特殊,就是寻找长度最小的非子串
乍一看没法写,所以在比赛中果断给放弃了,比完之后仔细一想,还是可以写的。
可以知道需要寻找的非子串只由2种字符组成,一种是’k’,另一种是’o’,所以我们就可以分别用二进制的’0’和’1’来表示,之所以用’0’表示’k’是因为题目中要求优先输出字典序小的一个。
通常来讲这个非子串不会太长,太长的话就真的没法解了(后面证实确实不会太长)。所以我们就可以直接暴力枚举,先枚举非子串的长度,再利用二进制枚举具体每个非子串的形式,然后与原串进行比较,如不是原串的子串即为答案,由于我们先前规定了’k’为’0’所以第一个找到的非子串就是字典序最小的。具体见代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <stack>
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
const int maxn = 500005;
const int maxc = 2000000;
int len;
bool mp[maxc];
char str[maxn];
int main(){
scanf("%s", str);
len = strlen(str);
for(int i = 1; ; i++){
bool flag = false;
memset(mp, false, sizeof(mp));
//预先处理出str串中长度为i的所有子串
int t = 0, k = 0, p = ~(1<<i), j = 0;
while(k < i){
t <<= 1;
if(str[k] == 'o')
t |= 1;
k++;
}
mp[t] = 1;
while(k < len){
t <<= 1;
//将t右移之后,必须将高位设置为0,这样才能保证这个串t的长度始终为i
t &= p;
if(str[k] == 'o')
t |= 1;
mp[t] = 1;
++k;
}
//枚举长度为i的所有子串
while(j < (1<<i)){
if(mp[j] == 0){
flag = true;
break;
}
j++;
}
if(flag){
vector<char> ans;
while(i--){
if(j & 1) ans.push_back('o');
else ans.push_back('k');
j >>= 1;
}
for(int i = ans.size()-1; i >= 0; --i)
putchar(ans[i]);
putchar('\n');
return 0;
}
}
return 0;
}
以上就是AC代码,经过运行还挺快的,也就基本上能确定这个非子串不会太长。