【后缀自动机】 HDU 5431 AB String

通道

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

思路:

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <iostream>
#include <bitset>

#define LL long long
#define pii pair <int, int>
#define xx first
#define yy second
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;

const int N = 20010;

char s[N], res[20][35];
int n, nx[N * 35][2], rt, r[N * 35], tot, cnt, fa[N * 35], e[N * 35];
LL a[20];
LL f[35];

int newnode (int f) {
    nx[tot][0] = nx[tot][1] = -1;
    e[tot] = 0; fa[tot] = f;
    return tot++;
}

void init () {
    tot = 0;
    cnt = 0;
    rt = newnode (-1);
}

void ins (int x, int y) {
    int now = rt;
    for (int i = x; i <= x + y - 1; i++) {
        if (nx[now][s[i]] == -1) nx[now][s[i]] = newnode (now);
        now = nx[now][s[i]];
    }
    if (e[now] == 0) e[now] = 1, cnt++;
}

void getres (char *res, int k, int l) {
    int now = rt;
    for (int i = 0, j = l - 1; i < l; i++, j--) {
        LL cl = f[j], cr = f[j];
        if (now != -1) {
            if (nx[now][0] != -1) cl -= e[nx[now][0]];
            if (nx[now][1] != -1) cr -= e[nx[now][1]];
        }
        if (k <= cl) {
            if (now != -1) now = nx[now][0];
            res[i] = ‘A‘;
        } else {
            k -= cl;
            if (now != -1) now = nx[now][1];
            res[i] = ‘B‘;
        }
    }
    res[l] = 0;
}

void solve () {
    int vis[20], c = 0;
    memset (vis, 0, sizeof vis);
    int len = strlen (s);
    for (int i = 0; i < len; i++) s[i] -= ‘A‘;
    for (int i = 1; i <= 33; i++) {
        init();
        if (len >= i) {
            for (int j = 0; i + j - 1 < len; j++) {
                ins (j, i);
            }
        }
        for (int j = tot - 1; j > 0; j--) e[fa[j]] += e[j];
        LL all = f[i] - cnt;
        for (int j = 1; j <= n; j++) if (!vis[j] && a[j] <= all) {
            c++;
            getres (res[j], a[j], i);
            vis[j] = 1;
        }
        if (c == n) break;
        for (int j = 1; j <= n; j++) a[j] -= all;
    }
    for (int i = 1; i <= n; i++)
        printf ("%s\n", res[i]);
}

int main () {
    f[0] = 1;
    for (int i = 1; i <= 33; i++) f[i] = f[i - 1] * 2;
    int T; scanf("%d", &T);
    while (T--) {
        scanf ("%s", s);
           scanf("%d", &n);
        for (int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
        }
        solve ();
    }
}

时间: 2024-10-20 01:34:01

【后缀自动机】 HDU 5431 AB String的相关文章

hdu 5008 Boring String Problem(后缀自动机构造后缀树)

hdu 5008 Boring String Problem(后缀自动机构造后缀树) 题意:给出一个字符串s,然后每次询问一个k,求s的所有子串中,字典序第k小的是谁?多个解,则输出最左边的那个 解题思路:这道题应该是为后缀树量身定制的吧.只要构造出了后缀树,然后按字典序遍历就可以得出每个节点包含的子串的字典序的范围了,而且必然是个连续的区间范围.但是我不会后缀树啊..比赛的时候突然想到,后缀自动机是可以构造后缀树的,虽然以前没写过,但还是硬着头皮上吧,居然还真的让我给撸出来了.我的做法是这样的

hdu 5853 Jong Hyok and String(广义后缀自动机)

题目链接:hdu 5853 Jong Hyok and String 题意: 给你n个字符串,m个询问,每次询问一个字符串 定义set(s)={(i,j)} 表示 s在第i个字符串中出现,且末尾位置为j. 对于一个询问,求set(Qi)=set(t) ,t串的数量. 题解: 如果是n=1,那么就是后缀自动机的一道裸题,答案就是Qi串匹配的最后一个节点x,ml[x]-ml[f[x]]. 现在是多个串,那么就建立一个广义后缀自动机.每次插入一个串后,将last=root,然后继续插下一个就行了. 最

[2018 ACM-ICPC 焦作赛区网络赛] H - String and Times(后缀自动机)

Now you have a string consists of uppercase letters, two integers AA and BB. We call a substring wonderful substring when the times it appears in that string is between AA and BB (A \le times \le BA≤times≤B). Can you calculate the number of wonderful

【后缀自动机】HDU 5343 MZL&#39;s Circle Zhou

通道 题意:从A,B分别取出子串X,Y,求多少种不同的X+Y 思路: 代码: #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int MAX_N = 200007; typedef unsigned long long ll; struct SAM { int val[MAX_N], fa[MAX_N], c[26][MAX_N]; int tot,

hdu 4622 Reincarnation(后缀数组|后缀自动机|KMP)

Reincarnation Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others) Total Submission(s): 2138    Accepted Submission(s): 732 Problem Description Now you are back,and have a task to do: Given you a string s consist of lo

HDU 4622 Reincarnation(后缀自动机)

[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=4622 [题目大意] 给出一个长度不超过2000的字符串,有不超过10000个询问,问[L,R]子串中出现的子串数目,相同子串不可重复计数. [题解] 考虑到字符串长度只有两千,我们对每个位置往后建立2000个后缀自动机, 这样子就能分别计算每个位置往后出现的字符串数目并保存, 对于sam上的一个节点来说,它的匹配长度与失配位置的匹配长度只差就是他们之间的子串, 所以,我们在建立sam可以同时计算

字符串(多串后缀自动机):HDU 4436 str2int

str2int Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 2082    Accepted Submission(s): 744 Problem Description In this problem, you are given several strings that contain only digits from '0'

hdu 5008 Boring String Problem(后缀数组)

题目链接:hdu 5008 Boring String Problem 题目大意:给定一个字符串,初始状态l,r为0,每次询问子串中字典序第l^r^v+1的子串区间,对于重复的输出下标小的. 解题思路:后缀数组,对给定字符串做后缀数组,然后根据height数组确定每个位置做为起点的子串有多少,然后二分查找确定起点位置,但是因为子串的重复的要输出下表小的,所以确定起点后还要确定字典序最小的下标. #include <cstdio> #include <cstring> #includ

hdu 4641 K-string(后缀自动机)

题目链接:hdu 4641 K-string 题意: 一开始给你一个字符串S,现在有m个操作. 1 x表示在当前字符串末端添加一个字符x. 2 表示查询当前出现次数超过k次的子串有多少个. 题解: 后缀自动机在线维护right集. 没插入一个字符,就沿着fail跳,如果当前节点大于等于k的就不用再跳了,显然之前的节点肯定已经大于等于k了. 然后一旦有新的节点等于k就记录一下当前新增加的子串个数. 1 #include<cstdio> 2 #include<cstring> 3 #d