spoj 7258 SUBLEX(求第k大字串

  其实对sam的拓扑排序我似懂非懂但是会用一点了。

  

/** @xigua */
#include <stdio.h>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <cstring>
#include <queue>
#include <set>
#include <string>
#include <map>
#include <climits>
#define PI acos(-1)
#define rep(a,b,c) for(int (a)=(b); (a)<(c); ++(a))
#define drep(a,b,c) for(int (a)=(b); (a)>(c); --(a))
#define CLR(x) memset(x, 0, sizeof(x))
#define sf scanf
#define pf printf
using namespace std;
typedef long long ll;
typedef double db;
const int maxn = 250005*2  + 1000;
const int ma = 1e5 + 1000;
const int mod = 1e9 + 7;
const int INF = 1e8 + 5;
const ll inf = 1e17 + 5;
const db eps = 1e-6;
const int MAXN = 2e5+1e3;
struct SAM{
    int ch[maxn<<1][26];
    int fa[maxn<<1], len[maxn<<1];
    int cnt, last, root;
    void init() {
        root=1;
        memset(ch, 0, sizeof(ch));
        memset(fa, 0, sizeof(fa));
        last=cnt=root;
    }
    void add(int c) {
        int p=last, np=last=++cnt;
        len[np]=len[p]+1;
        while(!ch[p][c] && p) {
            ch[p][c]=np;
            p=fa[p];
        }
        if (p==0)  fa[np]=1;
        else {
            int q = ch[p][c];
            if(len[p] + 1 == len[q]) {
                fa[np] = q;
            }
            else {
                int nq = ++cnt;
                len[nq] = len[p] + 1;
                memcpy(ch[nq], ch[q], sizeof ch[q]);
                fa[nq] = fa[q];
                fa[q] = fa[np] = nq;
                while(ch[p][c] == q && p) {
                    ch[p][c] = nq;
                    p = fa[p];
                }
            }
        }
    }
    int find(char *s) {
        int p=root, l=0, c=0;
        int lenn=strlen(s);
        for(int i = 0; i < lenn; i++) {
            if(ch[p][s[i] - ‘a‘]) {
                p = ch[p][s[i] - ‘a‘];
                c++;
            }
            else {
                while(p&&!ch[p][s[i]-‘a‘])  p=fa[p];
                if (!p)  c=0, p=1;
                else  c=len[p]+1, p=ch[p][s[i]-‘a‘];
            }
            l = max(l, c);
        }
        printf("%d\n", l);
    }
}sam;
char s[maxn];
int c[maxn<<1], pt[maxn<<1], f[maxn];
void innt() {
    memset(pt, 0, sizeof(pt));
    memset(c, 0, sizeof(c));
    memset(f, 0, sizeof(f));
}
void top() {
    for (int i=1; i<=sam.cnt; i++)
        c[sam.len[i]]++;
    for (int i=1; i<=sam.cnt; i++)
        c[i]+=c[i-1];
    for (int i=sam.cnt; i>=1; i--)
        pt[c[sam.len[i]]--]=i;      // /*拓扑排序*/ //
    for (int i=sam.cnt; i; i--) {
        f[pt[i]]=1;
        for (int j=0; j<26; j++) {
            f[pt[i]]+=f[sam.ch[pt[i]][j]];  //相同前缀的字符串个数
        }
    }
}
void solve() {
    innt();
    scanf("%s", s);
    int lenn=strlen(s);
    sam.init();
    for (int i=0; i<lenn; i++) {
        sam.add(s[i]-‘a‘);
    }
    top();
    int q;  scanf("%d", &q);
    while(q--) {
        int x;  scanf("%d", &x);
        int p=sam.root;
        /*我们找第k大的字串就在f上转移就好了*/
        while(x) {
            for (int i=0; i<26; i++) {
                if (sam.ch[p][i]) {
                    if (f[sam.ch[p][i]]>=x) {
                        putchar(‘a‘+i);
                        p=sam.ch[p][i];
                        --x; break;
                    }
                    else  x-=f[sam.ch[p][i]];
                }
            }
        }
        puts("");
    }
}
int main() {
    int t = 1, cas = 1;
   // freopen("in.txt", "r", stdin);
   // freopen("out.txt", "w", stdout);
    //scanf("%d", &t);
    while(t--) {
       // printf("Case %d: ", cas++);
        solve();
    }
    return 0;
}
时间: 2024-10-03 20:13:46

spoj 7258 SUBLEX(求第k大字串的相关文章

SPOJ SUBLEX 求第k小子串

题目大意: 对于一个给定字符串,找到其所有不同的子串中排第k小的子串 先构建后缀自动机,然后我们可以将整个后缀自动机看做是一个DAG图,那么我们先进行拓扑排序得到 *b[N] 对于每个节点记录一个sc值,表示当前节点往下走可以得到不同的字符串的个数 然后从后往前,每次到达一个节点,当前节点sc赋1,然后每个可以往下走的son节点,都把这个son上的sc加到当前节点上即可 接下来得到一个排名,从root开始走,从a~z循环,通过sc正确的找到下一个进入的节点 1 #include <cstdio>

leetcode——Longest Substring Without Repeating Characters 求链表中无重复字符的最大字串长度(AC)

mnesia在频繁操作数据的过程可能会报错:** WARNING ** Mnesia is overloaded: {dump_log, write_threshold},可以看出,mnesia应该是过载了.这个警告在mnesia dump操作会发生这个问题,表类型为disc_only_copies .disc_copies都可能会发生. 如何重现这个问题,例子的场景是多个进程同时在不断地mnesia:dirty_write/2 mnesia过载分析 1.抛出警告是在mnesia 增加dump

poj 1226 hdu 1238 Substrings 求若干字符串正串及反串的最长公共子串 2002亚洲赛天津预选题

题目:http://poj.org/problem?id=1226 http://acm.hdu.edu.cn/showproblem.php?pid=1238 其实用hash+lcp可能也可以,甚至可能写起来更快,不过我没试,我最近在练习后缀数组,所以来练手 后缀数组的典型用法之一----------------后缀数组+lcp+二分 思路:1.首先将所有的字符串每读取一个,就将其反转,作为一组,假设其下标为i到j,那么cnt[i]到cnt[j]都标记为一个数字(这个数字意思是第几个读入的字符

bzoj 3768: spoj 4660 Binary palindrome二进制回文串

Description 给定k个长度不超过L的01串,求有多少长度为n的01串S满足: 1.该串是回文串 2.该串不存在两个不重叠的子串,在给定的k个串中. 即不存在a<=b<c<=d,S[a,b]是k个串中的一个,S[c,d]是k个串中的一个 (It does not contain two non-overlapped substrings in the given list of K binary strings.) 举个例子,若给定2(k=2)个01串:101和1001 1010

HDU 5008西安网络赛B题:后缀数组求第k小子串

思路:尼玛,这题搞了一天了,比赛的时候用了n^2的方法绝对T了,然后今天看别人代码看了一天才知道.后面感觉也挺容易的,就是没想到,之前做过SPOJ 694 705求过不同子串了,知道怎么求不同子串个数了,但是比赛的时候这个技巧竟然抛在脑后了,然后就不会了. 但是今天自己用了自己的两个后缀数组的模板(倍增和DC3)的都WA了,搞得自己真想跳楼去了!! 到现在都不知道到底是哪里错了,处理的方法和标准做法都一样,但是就是WA,然后用了别人的模板,再用自己的处理方法就过了,怀疑自己的两个模板是不是哪里错

最大字串和

最大字串和: #include <iostream> using namespace std; //求最大字串和:返回最大和 int maxSubSum(int a[], int len) { int sum = 0; //全局最大值 int temp = 0; //局部最大值 for(int i = 0; i < len; ++i) { if(temp > 0) //如果局部最大值大于0,则继续求和,否则以数组当前元素重新初始化 { temp += a[i]; } else te

树状数组求第K小值 (spoj227 Ordering the Soldiers &amp;&amp; hdu2852 KiKi&#39;s K-Number)

题目:http://www.spoj.com/problems/ORDERS/ and http://acm.hdu.edu.cn/showproblem.php?pid=2852 题意:spoj227:告诉每个位置前面有多少个数比当前位置小,求出原序列.hdu2852:设计一个容器,支持几种操作:增加/删除元素,求容器中比a大的数中第k小的数是多少. 分析:两个题思路都是求数组里面的第K小的数.开始一直在找O(N*logN)的方法,后来发现O(N*logN*logN)也是可以过的...两步:和

【循环数组的最大字串和】Maximal-sum Subsequence

[循环数组的最大字串和]Maximal-sum Subsequence PROBLEM 题目描述 给一个 N×N 的矩阵 M,可以取连续的一段数(必须是横着或者竖着或者斜着,这个矩阵是循环的,具体如下).要求找到一个子序列,使得这个序列的和最大. 对于 N=8 的矩阵,如下序列都是合法的: ? M2,1,M2,2,M2,3,M2,4,M2,5,M2,6,M2,7,M2,8. ? M2,2,M2,3,M2,4. ? M2,6,M2,7,M2,8,M2,1,M2,2. ? M4,3,M5,3,M6,

求f(k)=k^k(k=1...n)的前n项和

求f(k)=k^k(k=1...n)的前n项和. 程序实现: #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> long long My_Mul_Sum(int *n)//封装了一个求k^k的前n项和的函数 { int k = 1; long long sum = 0;//定义为long long是为了防止数据较大,容易溢出 for (k = 1; k <= n; k++) { int count = 0, mul = 1;//count