【HDU-6223/2017ICPC沈阳G】Infinite Fraction Path(后缀数组+超级快读)

题目链接:https://vjudge.net/problem/HDU-6223

题目大意

给定一张图有 (N) 个点,编号为 (0,...,N-1),每个点都从自身有一条到点 (i^{2}+1) 的边(有向),点上有点权,点权为 (0,...,9),走过一条路径最终获得的字符串为点权字符串拼起来。问走 (N) 步,能得到的最大字符串为多少。

思路

后缀数组中有一个技巧是倍增进行比较,从而得到 (O(n log n)) 的复杂度,那么只要将后缀数组中的 (+w) 替换为 (to[u][w]) 进行倍增即可。

但是这样做会疯狂TLE,考虑到读入可能量很大,加上超级快读就过了。

AC代码

#include <bits/stdc++.h>

#define FI(n) FastIO::read(n)
#define FO(n) FastIO::write(n)
#define Flush FastIO::Fflush()
typedef long long ll;
using namespace std;

namespace FastIO {  // 超级快读
    const int SIZE = 1 << 16;
    char buf[SIZE], obuf[SIZE], str[60];
    int bi = SIZE, bn = SIZE, opt;
    double D[] = {0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001, 0.0000001, 0.00000001, 0.000000001, 0.0000000001};

    int read(char *s) {
        while (bn) {
            for (; bi < bn && buf[bi] <= ' '; bi++);
            if (bi < bn) break;
            bn = fread(buf, 1, SIZE, stdin);
            bi = 0;
        }
        int sn = 0;
        while (bn) {
            for (; bi < bn && buf[bi] > ' '; bi++) s[sn++] = buf[bi];
            if (bi < bn) break;
            bn = fread(buf, 1, SIZE, stdin);
            bi = 0;
        }
        s[sn] = 0;
        return sn;
    }

    bool read(int &x) {
        int n = read(str), bf = 0;
        if (!n) return 0;
        int i = 0;
        if (str[i] == '-') bf = 1, i++; else if (str[i] == '+') i++;
        for (x = 0; i < n; i++) x = x * 10 + str[i] - '0';
        if (bf) x = -x;
        return 1;
    }

    bool read(long long &x) {
        int n = read(str), bf;
        if (!n) return 0;
        int i = 0;
        if (str[i] == '-') bf = -1, i++; else bf = 1;
        for (x = 0; i < n; i++) x = x * 10 + str[i] - '0';
        if (bf < 0) x = -x;
        return 1;
    }

    void write(int x) {
        if (x == 0) obuf[opt++] = '0';
        else {
            if (x < 0) obuf[opt++] = '-', x = -x;
            int sn = 0;
            while (x) str[sn++] = x % 10 + '0', x /= 10;
            for (int i = sn - 1; i >= 0; i--) obuf[opt++] = str[i];
        }
        if (opt >= (SIZE >> 1)) {
            fwrite(obuf, 1, opt, stdout);
            opt = 0;
        }
    }

    void write(long long x) {
        if (x == 0) obuf[opt++] = '0';
        else {
            if (x < 0) obuf[opt++] = '-', x = -x;
            int sn = 0;
            while (x) str[sn++] = x % 10 + '0', x /= 10;
            for (int i = sn - 1; i >= 0; i--) obuf[opt++] = str[i];
        }
        if (opt >= (SIZE >> 1)) {
            fwrite(obuf, 1, opt, stdout);
            opt = 0;
        }
    }

    void write(unsigned long long x) {
        if (x == 0) obuf[opt++] = '0';
        else {
            int sn = 0;
            while (x) str[sn++] = x % 10 + '0', x /= 10;
            for (int i = sn - 1; i >= 0; i--) obuf[opt++] = str[i];
        }
        if (opt >= (SIZE >> 1)) {
            fwrite(obuf, 1, opt, stdout);
            opt = 0;
        }
    }

    void write(char x) {
        obuf[opt++] = x;
        if (opt >= (SIZE >> 1)) {
            fwrite(obuf, 1, opt, stdout);
            opt = 0;
        }
    }

    void Fflush() {
        if (opt) fwrite(obuf, 1, opt, stdout);
        opt = 0;
    }
};

const int MAXN = 150005;


int to[MAXN][22];

int sa[MAXN], rk[MAXN << 1], oldrk[MAXN << 1], id[MAXN], cnt[MAXN];

void run(int s[], int n) {
    int m = 10;
    for (int i = 0; i <= m; i++) cnt[i] = 0;
    for (int i = 1; i <= n; i++) ++cnt[rk[i] = s[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;

    int n2 = (n << 1);
    for (int i = n + 1; i <= n2; i++) oldrk[i] = rk[i] = 0;

    for (int w = 0; (1 << w) <= n; w++) {
        for (int i = 0; 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[to[id[i]][w]]];
        for (int i = 1; i <= m; i++) cnt[i] += cnt[i - 1];
        for (int i = n; i >= 1; i--) sa[cnt[rk[to[id[i]][w]]]--] = id[i];

        for (int i = 0; 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 = 0; i <= n; i++) oldrk[i] = rk[i];
        int p = 0;
        for (int i = 1; i <= n; i++) {
            if (oldrk[sa[i]] == oldrk[sa[i - 1]] && oldrk[to[sa[i]][w]] == oldrk[to[sa[i - 1]][w]]) rk[sa[i]] = p;
            else rk[sa[i]] = ++p;
        }
        m = p;
        if (p >= n) break;
    }
}

char str[MAXN];
int a[MAXN];

int main() {
    int T, kass = 1;
    FI(T);//scanf("%d", &T);
    while (T--) {
        int n;
        FI(n);// scanf("%d", &n);
        FI(str + 1);//scanf("%s", str + 1);
        for (int i = 1; i <= n; i++) {
            a[i] = str[i] - '0' + 1; // 1,2,..10
            to[i][0] = ((ll) (i - 1) * (i - 1) + 1) % n + 1;
        }

        for (int i = 1; i <= 20; i++) {
            for (int j = 1; j <= n; j++)
                to[j][i] = to[to[j][i - 1]][i - 1];
        }
        run(a, n);

        FO('C'), FO('a'), FO('s'), FO('e'), FO(' '), FO('#'), FO(kass++), FO(':'), FO(
                ' ');// printf("Case #%d: ", kass++);
        int tmp = sa[n];
        for (int i = 1; i <= n; i++) {
            FO(a[tmp] - 1);//printf("%d", a[tmp] - 1);
            tmp = to[tmp][0];
        }
        FO('
');// printf("
");
    }
    Flush;
}

附上一组测试数据:

2
10
0418499462
15
351222822042405

正解为:

Case #1: 9940419940
Case #2: 822212212212212
原文地址:https://www.cnblogs.com/tudouuuuu/p/14091196.html