4516: [Sdoi2016]生成魔咒

4516: [Sdoi2016]生成魔咒

链接

题意:

  求本质不同的子串。

分析:

  后缀数组或者SAM都可以。

  考虑SAM中每个点的可以表示的子串是一个区间min(S)~max(S),把每个点的这个区间加起来即可。

  字符集有点大,可以用map。

代码:

复制代码
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<cctype>
#include<set>
#include<queue>
#include<vector>
#include<map>
using namespace std;
typedef long long LL;

inline int read() {
    int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
}

const int N = 200005;
map<int,int> ch[N];
int fa[N], len[N], Index = 1, Last = 1;
LL Ans;

void extend(int c) {
    int np = ++Index, p = Last; 
    len[np] = len[p] + 1;
    for (; p && ch[p].find(c) == ch[p].end(); p = fa[p]) ch[p][c] = np;
    if (!p) fa[np] = 1;
    else {
        int Q = ch[p][c];
        if (len[Q] == len[p] + 1) fa[np] = Q;
        else {
            int NQ = ++Index;
            fa[NQ] = fa[Q];
            ch[NQ] = ch[Q];
            len[NQ] = len[p] + 1;
            fa[Q] = fa[np] = NQ;
            for (; p && ch[p].find(c) != ch[p].end() && ch[p][c] == Q; p = fa[p]) ch[p][c] = NQ;
        }
    }
    Last = np;
    Ans += len[np] - len[fa[np]]; // max(np)=len[np], min(np)=len[fa[p]] + 1
    printf("%lld\n", Ans);
}
int main() {
    int n = read(); 
    for (int i = 1; i <= n; ++i) {
        int x = read();
        extend(x);
    }
    return 0;
}
复制代码

 

posted @   MJT12044  阅读(160)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core内存结构体系(Windows环境)底层原理浅谈
· C# 深度学习:对抗生成网络(GAN)训练头像生成模型
· .NET 适配 HarmonyOS 进展
· .NET 进程 stackoverflow异常后,还可以接收 TCP 连接请求吗?
· SQL Server统计信息更新会被阻塞或引起会话阻塞吗?
阅读排行:
· 传国玉玺易主,ai.com竟然跳转到国产AI
· 本地部署 DeepSeek:小白也能轻松搞定!
· 自己如何在本地电脑从零搭建DeepSeek!手把手教学,快来看看! (建议收藏)
· 我们是如何解决abp身上的几个痛点
· 普通人也能轻松掌握的20个DeepSeek高频提示词(2025版)
点击右上角即可分享
微信分享提示