SAM习题集合

发现对SAM还是相当的不熟悉。。。专门开一个SAM练习好了。。。估计以后还要来个字符串恶补。。。

挖坑:3277 3473 3413 2806 2780 2555 3897

【bzoj3998】
求第k小子字符串,分算上重复和不算上重复。
十分地裸,如果不算重的话除了root以外所有节点的val都是1然后求sum,如果算的话就只是后缀节点的val是1然后再求sum。
很sb啦
然而把add写错了,查了半个小时QAQ

#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define maxn 2000007

typedef long long ll;
typedef int arr[maxn];
typedef int sam[maxn][26];

int n , tot , ed , T;
arr len , fa , cnt , tp ;
sam go;
int val[maxn] , sum[maxn] , K;

void add(int c , int l) {
    int p = ed , np = ed = ++ tot;
    len[np] = len[p] + 1, val[np] = 1;
    for(;p && !go[p][c];p = fa[p]) go[p][c] = np;
    if (!p)
        { fa[np] = 1 ; return ; }
    int q = go[p][c] ;
    if (len[q] == len[p] + 1)
        { fa[np] = q ; return ; }
    int r = ++ tot ; len[r] = len[p] + 1;
    memcpy(go[r] , go[q] , sizeof go[q]);
    for(fa[r] = fa[q] , fa[q] = fa[np] = r;go[p][c] == q;p = fa[p]) go[p][c] = r;
}

void tpsort() {
    rep(i , 1 , tot) cnt[len[i]] ++;
    rep(i , 1 , n  ) cnt[i] += cnt[i - 1];
    per(i , tot , 1) tp[cnt[len[i]] --] = i;
    per(i , tot , 1) {
        int u = tp[i];
        if (T) val[fa[u]] += val[u]; else val[u] = 1;
    }
    val[1] = 0;
    per(i , tot , 1) {
        int u = tp[i];
        sum[u] = val[u];
        rep(c , 0 , 25) sum[u] += sum[go[u][c]];
    }
}

void dfs(int u) {
    if (K <= val[u]) return ;
    K -= val[u];
    rep(i , 0 , 25) {
        int v = go[u][i];
        if (!v) continue;
        if (sum[v] >= K) {
            putchar(i + 'a');
            dfs(v);
            return;
        }
        K -= sum[v];
    }
}

void input() {
    ed = tot = 1;
    for(char c = getchar();c <= 'z' && c >= 'a';c = getchar()) add(c - 'a' , n ++);
    scanf("%d%d" , &T , &K);
}

void solve() {
    tpsort();
    if (sum[1] < K) puts("-1");
    else dfs(1);
}

int main() {
    #ifndef ONLINE_JUDGE
        freopen("data.txt" , "r" , stdin);
        freopen("data.out" , "w" , stdout);
    #endif
    input();
    solve();
    return 0;
}

【bzoj3172】
做了半年的题啊哈哈哈哈哈哈
以此达成bzoj 100A
强行用SAM代替AC自动机啊哈哈哈哈哈
脑残写法

#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define maxn 2500007

typedef int arr[maxn];
typedef int sam[maxn][27];

arr len , val , fa , cnt , tp;
sam go;
char str[maxn];
int n , l , tot , ed;

void add(int c) {
    int p = ed , np = ed = ++ tot ;
    len[np] = len[p] + 1;
    val[np] = 1;
    for(;p && !go[p][c];p = fa[p]) go[p][c] = np;
    if (!p)
        { fa[np] = 1 ; return ; }
    int q = go[p][c];
    if (len[q] == len[p] + 1)
        { fa[np] = q ; return ; }
    int r = ++ tot ; len[r] = len[p] + 1;
    memcpy(go[r] , go[q] , sizeof go[q]);
    for(fa[r] = fa[q] , fa[q] = fa[np] = r;go[p][c] == q;p = fa[p]) go[p][c] = r;
}

void tpsort() {
    rep(i , 1 , tot) cnt[len[i]] ++;
    rep(i , 1 , l  ) cnt[i] += cnt[i - 1];
    per(i , tot , 1) tp[cnt[len[i]] -- ] = i;
    per(i , tot , 1) val[fa[tp[i]]] += val[tp[i]];
}

void input() {
    scanf("%d" , &n) , getchar();
    ed = tot = 1;
    rep(i , 1 , n) {
        for(char c = getchar();c <= 'z' && c >= 'a';c = getchar()) add(c - 'a') , str[++ l] = c;
        str[++ l] = 'a' + 26;
        add(26);
    }
}

void solve() {
    tpsort();
    int j = 0;
    rep(i , 1 , n) {
        int u = 1;
        while (str[++ j] != 'a' + 26) u = go[u][str[j] - 'a'];
        printf("%d\n" , val[u]);
    }
}

int main() {
    #ifndef ONLINE_JUDGE
        freopen("data.txt" , "r" , stdin);
        freopen("data.out" , "w" , stdout);
    #endif
    input();
    solve();
    return 0;
}

你可能感兴趣的:(SAM习题集合)