【后缀自动机或二分】 HDU 5431 AB String

通道

题意:给出只有AB组成的字符串S,求第k个不在S中出现的串T。

思路:我们可以把原串中logK左右的串都拿出来排序。然后直接二分答案求解即可

代码:

#include <cstdio>
#include <string>
#include <cstring>
#include <vector>
#include <algorithm>

using namespace std;

typedef long long ll;
const int MAX_N = 20005;
char s[MAX_N];
vector<int> val(MAX_N);
inline void solve() {
    scanf("%s", s);
    int sz = strlen(s);
    fill(val.begin(), val.end(), 0);
    vector<ll> h[35];
    vector<ll> sm(35, 0);
    for (int i = 1; i <= 32; ++i) {
        for (int j = 0; j + i - 1 < sz; ++j) {
            val[j] = (val[j] << 1) + (s[j + i - 1] - 'A');
            h[i].push_back(val[j]);
        }
        sort(h[i].begin(), h[i].end());
        h[i].resize(unique(h[i].begin(), h[i].end()) - h[i].begin());
        sm[i] = sm[i - 1] + ((1ll << i) - h[i].size());
    }
    int N;
    ll K;
    scanf("%d", &N);
    while (N--) {
        scanf("%lld", &K);
        int pos = lower_bound(sm.begin(), sm.end(), K) - sm.begin();
        ll l = 0, r = (1ll << pos) - 1;
        while (l <= r) {
            ll mid = (l + r) / 2;
            int idx = upper_bound(h[pos].begin(), h[pos].end(), mid) - h[pos].begin();
            ll cnt = sm[pos - 1] + mid + 1ll - idx;
            if (cnt < K) l = mid + 1;
            else if (cnt > K) r = mid - 1;
            else if (idx > 0 && h[pos][idx - 1] == mid) r = mid - 1;
            else {
                string res;
                for (int j = 0; j < pos; ++j) {
                    if ((1ll << j) & mid) res = "B" + res;
                    else res = "A" + res;
                }
                printf("%s\n", res.c_str());
                break;
            }
        }
    }
}
int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        solve();
    }
    return 0;
}
View Code

 

思路:设F[i][j]表示到SAM上的状态i,还有长度j时有多少可能的T串数量

以下是后缀自动机代码:

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long ll;

const int MAX_N = 20007;

struct SAM {
    int val[MAX_N], fa[MAX_N], c[2][MAX_N];
    int tot, last;
    ll dp[MAX_N][33];
    inline int newNode(int step) {
        val[++tot] = step;
        fa[tot] = 0;
        for (int i = 0; i < 2; ++i) c[i][tot] = 0;
        return tot;
    }
    inline void extend(int k) {
        int p = last;
        int np = newNode(val[last] + 1);
        while (p && !c[k][p]) c[k][p] = np, p = fa[p];
        if (!p) fa[np] = 1;
        else {
            int q = c[k][p];
            if (val[q] == val[p] + 1) fa[np] = q;
            else {
                int nq = newNode(val[p] + 1);
                for (int i = 0; i < 2; ++i) c[i][nq] = c[i][q];
                fa[nq] = fa[q]; 
                fa[q] = fa[np] = nq;
                while (p && c[k][p] == q) c[k][p] = nq, p = fa[p];
            }
        }
        last = np;
    }
    inline int add(int k) {
        extend(k);
    }
    inline void init() {
        tot = 0;
        last = newNode(0);
    }
} suf;

char str[MAX_N];
int c[MAX_N], sa[MAX_N];

int main() {
    int T;scanf("%d", &T);
    while (T-- > 0) {
        scanf("%s", str);
        int len = strlen(str);
        suf.init();
        for (int i = 0; str[i]; ++i) suf.add(str[i] - 'A');
        memset(c, 0, sizeof c);
        for (int i = 1; i <= suf.tot; ++i) ++c[suf.val[i]];
        for (int i = 1; i <= len; ++i) c[i] += c[i - 1];
        for (int i = 1; i <= suf.tot; ++i) sa[c[suf.val[i]]--] = i;
        for (int i = suf.tot; i > 0; --i) {
            int id = sa[i];
            suf.dp[id][0] = 0;
            for (int k = 1; k < 33; ++k) {
                suf.dp[id][k] = 0;
                for (int j = 0; j < 2; ++j) {
                    if (suf.c[j][id]) suf.dp[id][k] += suf.dp[suf.c[j][id]][k - 1];
                    else suf.dp[id][k] += (1ll << (k - 1));
                }
            }
        }
        int n; scanf("%d", &n);
        while (n--) {
            ll K; scanf("%I64d", &K);
            int depth = 0;
            ll now = 0;
            for (int i = 1; i < 33; ++i) {
                now += suf.dp[1][i];
                if (now >= K) {
                    depth = i;
                    break;
                }
            }
            for (int i = 1; i < depth; ++i) 
                K -= suf.dp[1][i];
            int id = 1;
            while(depth > 0) {
                ll t0 = 0;
                if (suf.c[0][id]) t0 = suf.dp[suf.c[0][id]][depth - 1];
                else t0 = 1ll << (depth - 1);
                if(K <= t0) {
                    if (suf.c[0][id]) {
                        --depth;
                        id = suf.c[0][id];
                        putchar('A');
                    } else {
                        --K;
                        putchar('A');
                        for(int i = depth - 2; i >= 0; --i) 
                            if(K & (1LL << i)) putchar('B');
                            else putchar('A');
                        break;
                    }
                } else {
                    K -= t0;
                    if (suf.c[1][id]) {
                        --depth;
                        id = suf.c[1][id];
                        putchar('B');
                    } else {
                        --K;
                        putchar('B');
                        for(int i = depth - 2; i >= 0; --i) 
                            if(K & (1LL << i)) putchar('B');
                            else putchar('A');
                        break;
                    }
                }
            }
               puts("");
        }
    }
    return 0;
}
View Code

 

posted @ 2015-09-20 11:00  mithrilhan  阅读(247)  评论(0编辑  收藏  举报