2022-03-24每日刷题打卡
代码源——每日一题
循环子串 - 题目 - Daimayuan Online Judge
题目描述
一个字符串SS是另一字符串T的循环子串当且仅当存在k, T所有字符循环右移k位后得到的新串T′T′,满足SS是T′T′的子串。
例如: abc
是 cefab
的循环子串。 (cefab
循环右移22位得到abcef
, abc
是abcef
的子串)
一个串PP是完全循环串当且仅当对于它的任一子串H, 都有HreverseHreverse是PP的循环子串 (HreverseHreverse 为 H的倒转, 如abc
reverse后 为cba
)。
给一个长度为n的字符串, 判断它是不是完全循环串。
输入格式
第一行一个正整数t, 表示测试数据组数。
对于每一组数据,第一行一个正整数n, 表示字符串的长度。接下来一行一个长度为n的字符串. 仅包含小写字母。
输出格式
对于每组测试数据,如果这个串是完全循环串, 输出YES
,否则输出NO
。每组测试数据之间输出换行。
数据范围
对于所有数据 有 1≤t≤100, 1≤n≤10^3, ∑n≤10^3。
样例输入
2
4
ccca
11
eeaafbddfaa
样例输出
YES
NO
这题题目描述怪怪的,但意思就是说,字符串s的所有子串翻过来之后(abc变cba)能在s里找到一样的字符串,这个s可以是向右移动k次之后的样子(向右移动k次相当于把前面k个字符移动到末尾,比如abcde移动2次,那就变成cdeab)。
那么我们只要枚举所有可能的子串,然后在旋转后的字符串s里找看是不是都能找到即可,如果都能找到那就输出yes,一个找不到都要输出no。可是每次都要移动字符串s太麻烦了,所以我们要对字符串做点改变。
就像我们前面说的,移动k次是把前k个字符删除移动到末尾,那么最多移动len(字符串长度)次,字符串就会变回原样,那我们直接把一个相同的字符串s接到s后面即可,这样就可以在这个字符串里找到所有可能移动过后的字符串s,我们在这里面找子串即可。
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#define endl '\n';
typedef long long ll;
typedef pair<ll, ll>PII;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while (t--)
{
int n;
string s;
cin >> n >> s;
bool flag = true;
string str = s + s;
for (int len = 2; len <= n; len++)
{
for (int i = 0; i + len <= n; i++)
{
string res = s.substr(i, len);
reverse(res.begin(), res.end());
if (str.find(res) == str.npos)
{
cout << "NO" << endl;
flag = false;
break;
}
}
if (!flag)break;
}
if (flag)cout << "YES" << endl;
}
return 0;
}