http://www.ifrog.cc/acm/problem/1054
问删除一个字符后的最小循环节是多少、
比赛的时候想不出,不知道怎么暴力。
赛后看了别人代码才晓得。唉,还以为自己字符串还不错,但是变了一点点就不懂了。
1、可以暴力枚举循环节长度i,必要条件是(lenstr - 1) % i == 0。这是必须的,因为必须是倍数,关于约数的个数:(不大)
http://vfleaking.blog.163.com/blog/static/174807634201341913040467/
2、怎么判断这个循环节可行呢?
比如我有Habcabcabc,枚举了3,那么怎么判断3是可行的呢?
关键是利用扫描的思想。
记录cnt表示匹配了多少个,那么只需匹配6个就证明可行。
第一,'H' != 'c',cnt设置为0,表明一个也没匹配成功。
第二步,'a'和'a'成功。然后第三步'b'和'b'成功,'c'和'c'成功,竟然能变成枚举了"abc",然后就这样一直枚举下去。
这和我以前写的不同,Hab|cab|cab|c,我以前的是很死板的分段,现在这个不但能满足要求(求出正常的解,就是abcabcabc这样一样能枚举3是ans),还能忽视某些值,例如这里忽视了H。。
所以说怎么用O(n)判断可不可行,也是有技巧的。(这个能求出满足循环节为3的最大长度)
但是还是不能满足题目,例如aabaa,只能求出是循环节是1的时候长度是2,怎么模拟删除一个字符呢?
答案是把字符串写两次。变成aabaa|aabaa。。就是相当于反向的字符串了,那么既然循环,反向或者旋转与否不影响。
例如aHbcabcabc|aHbcabcabc。
这个变成了bcabcabca。。ans = 3;
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL; #include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
const int maxn = + ;
char str[maxn * ];
void work() {
int lenstr;
cin >> lenstr;
cin >> str + ;
int t = ;
for (int i = lenstr + ; i <= * lenstr; ++i) {
str[i] = str[t++];
}
str[ * lenstr + ] = '\0';
int ans = lenstr - ;
t = lenstr - ;
for (int i = ; i <= t; ++i) {
if (t % i != ) continue;
int cnt = ;
for (int j = ; j + i <= * lenstr; ++j) {
if (str[j] == str[j + i]) {
cnt++;
if (cnt == t - i) {
cout << t / i << endl;
return;
}
} else cnt = ;
}
}
cout << << endl;
return;
} int main() {
#ifdef local
freopen("data.txt","r",stdin);
#endif
IOS;
int t;
cin >> t;
while (t--) work();
return ;
}