ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF126B password SAM做法

2022-08-05 13:01:43  阅读:112  来源: 互联网

标签:sam SAM CF126B pos int num maxn ans password


题意

找出 \(S\) 的最长的子串 \(T\),满足 \(T\) 是 \(S\) 的前缀、后缀,并在中间出现过。不存在则输出 Just a Legend

思路如下:

  • 题目要求目标串是 Border,并且在中间出现过,即要求子串是 Border ,并且出现次数大于等于 3 次。
  • 那么我们记录字符串末尾在 SAM 中的位置 pos,然后跳它到根的后缀链接,显然途中经过的子串集合一定是 \(S\) 串的后缀,但它不一定是前缀,那么如何知道它是前缀呢?
  • 首先记录每个节点的 \(right\) (endpos) 集合大小为 num[] 。然后记录每个节点的 \(right\) 集合的最小值为 rightmin[]
  • 然后我们就从 pos 节点往上跳后缀链接树,判断每个节点的最大长度是否大于 rightmin 的值并且出现次数(更正式地, \(|right|\geq 3\)),满足条件就更新一下答案,至于用最大长度还是 rightmin 值去更新。
  • 时间复杂度 \(O(n)\) 。

Solution

#include<bits/stdc++.h>
typedef long long ll;
typedef std::pair<int, int> PII;
typedef std::pair<ll, ll> PLL;
typedef unsigned long long ull;
typedef double db;
#define re _read
#define arr(x) (x).begin(),(x).end()
#define get_sz(v) (int)v.size()
#define fi first
#define se second
#define pb push_back
#define endl "\n"
using namespace std;
template <class T> inline void _read(T& x) {
    static long long ans;
    static unsigned int c;
    static bool p;
    for (c = getchar(); c != '-' && (c < '0' || c > '9'); c = getchar()) ;
    if (c == '-')
        p = false, c = getchar();
    else
        p = true;
    for (ans = 0; c <= '9' && c >= '0'; c = getchar())
        ans = ans * 10 + c - '0';
    x = p ? ans : -ans;
}
/*====================================================================================================================================================================================*/
const int N = 1e6 + 10;
char s[N];
int pos;

const int maxn = 1e6 + 10;
struct SAM {
    //basic
    const char* s;
    int last, cnt, len;
    int nxt[maxn * 2][26],fa[maxn * 2],l[maxn * 2], rightmin[maxn * 2];
    //extension
    int cntA[maxn * 2], id[maxn * 2];/*辅助拓扑更新*/
    int num[maxn * 2];/*每个节点代表的所有串的出现次数*/
    SAM () { clear(); }
    void clear() {
        last = cnt = 1, l[1] = fa[1] = 0, memset(nxt[1], 0, sizeof nxt[1]);
    }
    void init(const char * str, int _len) {
        s = str, len = _len;
        for (int i = 1; i <= _len; i++)
            extend(str[i] - 'a', i);
    }
    void extend(int c, int idx) {
        int p = last, np = ++cnt;
        rightmin[np] = idx;
        if (idx == len) pos = np;
        memset(nxt[cnt], 0, sizeof nxt[cnt]);
        l[np] = l[p] + 1, last = np;
        while (p && !nxt[p][c]) nxt[p][c] = np, p = fa[p];
        if (!p) fa[np] = 1;
        else {
            int q = nxt[p][c];
            if (l[q] == l[p] + 1) fa[np] = q;
            else {
                int nq = ++cnt;
                rightmin[nq] = rightmin[q];
                l[nq] = l[p] + 1;
                memcpy(nxt[nq], nxt[q], sizeof(nxt[q]));
                fa[nq] = fa[q], fa[np] = fa[q] = nq;
                while (nxt[p][c] == q) nxt[p][c] = nq, p = fa[p];
            }
        }
    }
    void build() {
        memset(cntA, 0, sizeof cntA);
        memset(num, 0, sizeof num);
        for (int i = 1; i <= cnt; i++) cntA[l[i]]++;
        for (int i = 1; i <= cnt; i++) cntA[i] += cntA[i - 1];
        for (int i = cnt; i >= 1; i--) id[cntA[l[i]]--] = i;
        /*更新主串节点*/
        int temp = 1;
        for (int i = 1; i <= len; i++) {
            num[temp = nxt[temp][s[i] - 'a']] = 1;
        }
        /*拓扑更新*/
        for (int i = cnt; i >= 1; i--) {
            // basic
            int x = id[i];
            num[fa[x]] += num[x];
            // extension
        }
        // extension
    }
    void debug(){
        for (int i = cnt; i >= 1; i--){
            printf("num[%d]=%d l[%d]=%d fa[%d]=%d\n",i,num[i],i,l[i],i,fa[i]);
        }
    }
}sam;

int main() {
    scanf("%s", s + 1);
    int len = strlen(s + 1);
    sam.init(s, len);
    sam.build();
    int ans = 0;
    while (pos) {
        if (sam.num[pos] >= 3 & sam.l[pos] >= sam.rightmin[pos]) ans = max(ans, sam.rightmin[pos]);
        pos = sam.fa[pos];
    }
    if (!ans) puts("Just a legend");
    else {
        for (int i = 1; i <= ans; i++)
            printf("%c", s[i]);
    }
    return 0;
}

标签:sam,SAM,CF126B,pos,int,num,maxn,ans,password
来源: https://www.cnblogs.com/Roshin/p/CF126B.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有