对于一个首尾相接的数组,设其旋转k1、k2、k3...次后可以恢复原状。
且k1<k2<k3<...。
则可以肯定,k1为这个数组的循环节,且k2、k3...均为k1的倍数。
一种求循环节的方法为:
对长度为n的循环字符串,先从小到大遍历可能的循环节的长度i,判断是否n%i==0,然后对其中的除第一个循环节内的每一个字符进行判断
参考代码如下(By * A_G, contest: Codeforces Round #797 (Div. 3), problem: (F) Shifting String)
int period(string& s) { int n = s.size(); for (int i = 1; i <= n/2; i++) { if (n%i == 0) { bool good = 1; for (int j = i; j < n; j++) { if (s[j-i] != s[j]) { good = 0; break; } } if (good) return i; } } return n; }View Code
例题 Codeforces Round #797 (Div. 3) F. Shifting String
https://codeforces.com/contest/1690/problem/F
代码如下
#include<bits/stdc++.h> using namespace std; typedef long long LL; LL gcd(LL num1, LL num2) { if (num1%num2 == 0) return num2; return gcd(num2, num1%num2); } void YD() { int n; cin >> n; string str; cin >> str; vector<int> p(n); for (int i = 0; i < n; i++) { cin >> p[i]; p[i]--; } vector<bool> vis(n,false); LL ans = 1; for (int i = 0; i < n; i++) { if (!vis[i]) { string cir; cir+=(str[i]); vis[i] = true; int cur = p[i]; while (cur != i) { cir += (str[cur]); vis[cur] = true; cur = p[cur]; } int nn = cir.size(); for (int ii = 1; ii <= nn / 2; ii++) { if (nn%ii == 0) { bool flag = true; for (int jj = ii; jj < nn; jj++) { if (cir[jj] != cir[jj - ii]) { flag = false; break; } } if (flag) { nn = ii; break; } } } ans = ans / gcd(ans, LL(nn))*LL(nn); } } cout << ans << endl; } int main() { ios_base::sync_with_stdio(0); cin.tie(0); int T; cin >> T; while (T--) { YD(); } }View Code