2019牛客暑期多校训练营(第七场)A-String 【字符串最小表示法+暴力枚举】
题目:https://ac.nowcoder.com/acm/contest/887/A
大致题意:
给你一个01字符串,要求你用最少的割法,将该字符串分割成数个部分,每个部分都要求是一个对于其自身循环字典序最小的字符串。
参考资料:https://www.cnblogs.com/XGHeaven/p/4009210.html
字符串的最小表示法
思路:
因为数据非常小,字符串长度不超过200,所以即使是O(n^3)也不会TLE,所以不断从原字符串中暴力枚举起点,构造出一个子串,判断其是否是最小表示法,是则输出,否则枚举下一个起点。
代码:
#include<bits/stdc++.h>
using namespace std;
//返回值:该字符串最小表示时应当作为起点的字符的下标
int getmin(char *s, int n) {
int i=0,j=1,k=0,t;
while(i<n && j<n && k<n) {
t=s[(i+k)%n]-s[(j+k)%n];
if(!t)
k++;
else {
if (t>0) i+=k+1;
else j+=k+1;
if (i==j) j++;
k=0;
}
}
return i<j?i:j;
}
int main() {
int cas;
while(~scanf("%d",&cas)) {
getchar();
while(cas--) {
char ss[1000], temp[1000], count = 0;
scanf("%s",ss);
getchar();
int lenss = strlen(ss);
for(int i = 0; i < lenss; i++) {
int j;
for(j = lenss-1; j >= i; j--) {
for(int k = i; k <= j; k++) {
temp[count++] = ss[k];
}
temp[count] = '\0';
// printf("//%s//\n",temp);
int ret = getmin(temp, count);
//如果子串的开头就是返回值的话
//说明该子串就是符合条件的子串
if(ret == 0) {
//构造子串
for(int k = 0; k < count; k++)
printf("%c",temp[k]);
//这个i=j很关键
//让i指针直接跳到下一部分的起点位置
i = j;
if(i + 1 < lenss)
printf(" ");
count = 0;
break;
}
count = 0;
}
}
printf("\n");
}
}
return 0;
}
后话:
其实这道题有很多花式解法,这个比较好理解,而且较为通用,至少学到了“字符串的最小/最大表示法”这个新知识。但其实还有O(n)时间复杂度的解法,可以参考这位大佬的博客:
https://blog.csdn.net/weixin_43911945/article/details/98942043