Infinite Fraction Path (后缀数组)

题意

source

思路

求每一位开始的字符串中字典序最小的字符串,容易想到用后缀数组。预处理出每一位开始跳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;
    }
}
posted @ 2021-05-12 20:18  limil  阅读(115)  评论(0编辑  收藏  举报