Infinite Fraction Path (后缀数组)
题意
思路
求每一位开始的字符串中字典序最小的字符串,容易想到用后缀数组。预处理出每一位开始跳2的幂次后位置,然后稍微修改一下后缀数组模板倍增部分即可。
使用普通排序的版本会T,得用计数排序。
#include <iostream>
#include <algorithm>
// #define endl '\n'
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define FILE freopen(".//data_generator//in.txt","r",stdin),freopen("res.txt","w",stdout)
#define FI freopen(".//data_generator//in.txt","r",stdin)
#define FO freopen("res.txt","w",stdout)
#define mp make_pair
#define seteps(N) fixed << setprecision(N)
typedef long long ll;
using namespace std;
/*-----------------------------------------------------------------*/
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
const int N = 2e5 + 10;
int sa[N], rk[N], oldrk[N], id[N], cnt[N];
int arr[N];
int up[25][N];
int main() {
// IOS;
int cas = 0;
int t;
cin >> t;
while(t--) {
int n;
cin >> n;
int m = max(10, n);
for(int i = 0; i < n; i++) {
char ch;
cin >> ch;
arr[i + 1] = ch - '0';
up[0][i + 1] = (1ll * i * i + 1) % n + 1;
}
for(int i = 1; (1 << i) <= n; i++) {
for(int j = 1; j <= n; j++) {
up[i][j] = up[i - 1][up[i - 1][j]];
}
}
for(int i = 1; i <= n; i++) {
rk[i] = arr[i] + 1;
}
for(int i = 1; i <= m; i++) cnt[i] = 0;
for (int i = 1; i <= n; ++i) ++cnt[rk[i]];
for (int i = 1; i <= m; ++i) cnt[i] += cnt[i - 1];
for (int i = n; i >= 1; --i) sa[cnt[rk[i]]--] = i;
for (int po = 0, w = 1; w < n; w <<= 1, po++) {
for(int i = 1; i <= m; i++) cnt[i] = 0;
for (int i = 1; i <= n; ++i) id[i] = sa[i];
for (int i = 1; i <= n; ++i) ++cnt[rk[up[po][id[i]]]];
for (int i = 1; i <= m; ++i) cnt[i] += cnt[i - 1];
for (int i = n; i >= 1; --i) sa[cnt[rk[up[po][id[i]]]]--] = id[i];
for(int i = 1; i <= m; i++) cnt[i] = 0;
for (int i = 1; i <= n; ++i) id[i] = sa[i];
for (int i = 1; i <= n; ++i) ++cnt[rk[id[i]]];
for (int i = 1; i <= m; ++i) cnt[i] += cnt[i - 1];
for (int i = n; i >= 1; --i) sa[cnt[rk[id[i]]]--] = id[i];
for(int i = 1; i <= n; i++) oldrk[i] = rk[i];
for (int p = 0, i = 1; i <= n; ++i) {
if (oldrk[sa[i]] == oldrk[sa[i - 1]] &&
oldrk[up[po][sa[i]]] == oldrk[up[po][sa[i - 1]]]) {
rk[sa[i]] = p;
} else {
rk[sa[i]] = ++p;
}
}
}
cout << "Case #" << ++cas << ": ";
int cur = sa[n] - 1;
for(int i = 1; i <= n; i++) {
cout << arr[cur + 1];
cur = (1ll * cur * cur + 1) % n;
}
cout << endl;
}
}