Prinzessin der Verurteilung:最短未出现字符串的板子。

思路

考虑在 SAM 上 dp,定义 \(dp_i\) 表示从 \(i\) 节点走到 NULL 节点所花费的最少步数。显然我们建出反图,跑 DAG 上 dp 即可。转移如下:

\[dp_i=1+\min_{j=1}^{|v_i|}dp_{v_{i,j}}
\]

输出方案的话记录下每个 dp 值的先驱,最后从 \(1\) 号节点开始遍历一遍即可。

注意,如果某个节点某个字母的转移边不存在的话,也需要建边,可以用一个超级源点 \(0\) 把这些 SAM 上不存在的边记录下来,这样才能算出不在里面出现过的字符串。

时间复杂度 \(O(tn|\sum|)\),应该是最优复杂度了。

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define lc (p<<1)
#define rc ((p<<1)|1)
#define eb(x) emplace_back(x)
#define pb(x) push_back(x)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
using pi=pair<int,int>;
int n,len[2005],fa[2005],ch[2005][26],tot=1,np=1,rd[2005];
char s[1005];
vector<pi>g[2005];
struct node{
int v=0x3f3f3f3f,frm=-1,cx=-1;
}dp[2005];
void init()
{
for(int i=0;i<=tot;i++)
{
len[i]=fa[i]=0;
for(int j=0;j<26;j++)ch[i][j]=0;
dp[i]={0x3f3f3f3f,-1,-1};
rd[i]=0;
g[i].clear();
}
tot=np=1;
}
void extend(int c)
{
int p=np;
np=++tot;
len[np]=len[p]+1;
for(;p&&ch[p][c]==0;p=fa[p])ch[p][c]=np;
if(p==0)fa[np]=1;
else
{
int q=ch[p][c];
if(len[q]==len[p]+1)fa[np]=q;
else
{
int nq=++tot;
len[nq]=len[p]+1;
fa[nq]=fa[q],fa[q]=nq,fa[np]=nq;
for(;p&&ch[p][c]==q;p=fa[p])ch[p][c]=nq;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
}
}
}
void outp()
{
int p=1;
while(p!=-1)
{
int v=dp[p].frm,c=dp[p].cx;
if(c<0)break;
cout<<char(c+'a');
p=v;
}
cout<<'\n';
}
void solve()
{
cin>>n>>s+1;
init();
for(int i=1;i<=n;i++)extend(s[i]-'a');
for(int i=1;i<=tot;i++)
{
for(int j=0;j<26;j++)
{
int v=ch[i][j];
g[v].push_back({i,j});
rd[i]++;
}
}
queue<int>q;
for(int i=0;i<=tot;i++)
{
if(rd[i]==0)
{
dp[i]={1,-1,-1};
q.push(i);
}
}
while(!q.empty())
{
int u=q.front();
q.pop();
for(auto ed:g[u])
{
int v=ed.fi,c=ed.se;
rd[v]--;
if(rd[v]==0)q.push(v);
int dpv=dp[u].v+1;
if(dpv<dp[v].v)
{
dp[v].v=dpv;
dp[v].frm=u;
dp[v].cx=c;
}
else if(dpv==dp[v].v&&dp[v].cx>c)
{
dp[v].frm=u;
dp[v].cx=c;
}
}
}
outp();
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
cin>>t;
while(t--)solve();
return 0;
}

Codeforces 1536B Prinzessin der Verurteilung 题解 [ 紫 ] [ 后缀自动机 ] [ 动态规划 ] [ 拓扑排序 ]的更多相关文章

  1. 「2017 山东一轮集训 Day5」字符串 (后缀自动机, 拓扑排序)

    /** 首先通过SAM求出每个串本质不同的子串 然后发现转移不好处理整体的本质不同 形如串A可能状态有a,b,ab,空,串B可能状态有b,空两种, 那么我们需要处理ab + 空 和 a + b的情况 ...

  2. Codeforces Round #285 (Div. 2)C. Misha and Forest(拓扑排序)

    传送门 Description Let's define a forest as a non-directed acyclic graph (also without loops and parall ...

  3. 2021.07.17 题解 CF1385E Directing Edges(拓扑排序)

    2021.07.17 题解 CF1385E Directing Edges(拓扑排序) CF1385E Directing Edges - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) ...

  4. 洛谷 P4248 / loj 2377 [AHOI2013] 差异 题解【后缀自动机】【树形DP】

    可能是一个 SAM 常用技巧?感觉 SAM 的基础题好多啊.. 题目描述 给定一个长度为 \(n\) 的字符串 \(S\) ,令 \(T_i\) 表示它从第 \(i\) 个字符开始的后缀,求: \[ ...

  5. 洛谷 P3975 / loj 2102 [TJOI2015] 弦论 题解【后缀自动机】【拓扑排序】

    后缀自动机入门. 题目描述 为了提高智商,ZJY 开始学习弦论. 这一天,她在<String theory>中看到了这样一道问题:对于一个给定的长度为 \(n\) 的字符串,求出它的第 \ ...

  6. Codeforces Round #364 (Div. 1) (差一个后缀自动机)

    B. Connecting Universities 大意: 给定树, 给定2*k个点, 求将2*k个点两两匹配, 每个匹配的贡献为两点的距离, 求贡献最大值 单独考虑每条边$(u,v)$的贡献即可, ...

  7. codeforces 204E. Little Elephant and Strings(广义后缀自动机,Parent树)

    传送门在这里. 大意: 给一堆字符串,询问每个字符串有多少子串在所有字符串中出现K次以上. 解题思路: 这种子串问题一定要见后缀自动机Parent树Dfs序统计出现次数都是套路了吧. 这道题统计子串个 ...

  8. [codeforces 894 E] Ralph and Mushrooms 解题报告 (SCC+拓扑排序+DP)

    题目链接:http://codeforces.com/problemset/problem/894/E 题目大意: $n$个点$m$条边的有向图,每条边有一个权值,可以重复走. 第$i$次走过某条边权 ...

  9. Codeforces Round #541 (Div. 2) D(并查集+拓扑排序) F (并查集)

    D. Gourmet choice 链接:http://codeforces.com/contest/1131/problem/D 思路: =  的情况我们用并查集把他们扔到一个集合,然后根据 > ...

  10. Codeforces Round #285 (Div. 2) A B C 模拟 stl 拓扑排序

    A. Contest time limit per test 1 second memory limit per test 256 megabytes input standard input out ...

随机推荐

  1. PHP8新特性

    PHP 8.1 提供的功能 枚举 Fiber(纤维) never 返回类型 readonly 属性 final 类常量 新的 array_is_list() 函数 新的 fsync() 和 fdata ...

  2. Linux之SaltStack

    SaltStack是基于Python开发的一套C/S架构配置管理工具(功能不仅仅是配置管理,如使用salt-cloud配置AWS EC2实例),它的底层使用ZeroMQ消息队列pub/sub方式通信, ...

  3. 全球最大分类广告商的Karpenter实践:减负运维、减少中断、每月省21万(上)

    原文链接: https://medium.com/adevinta-tech-blog/the-karpenter-effect-redefining-our-kubernetes-operation ...

  4. 记录一次C#爬虫记录,获取必应图片

    记录一次C#爬虫记录,获取必应图片 起因 事情是这样的,我创建了一个仓库,里面有2018年到目前为止每日的必应壁纸,在八月份的时候我看到微软有接口文档,于是写了一个服务,每天早上八点钟会获取必应壁纸( ...

  5. CentOS 更换国内源

    前言 centos默认为官方yum源,国内使用的下载速度完全随缘,且不稳定,一般都需要更换国内源 过程 了解版本 通过cat /etc/redhat-release 可以获取当前centos的版本 知 ...

  6. Pro更改启动界面

    该方法适用于arcgispro 3.1及以上版本,我目前测试到3.3,是可以的. 使用的是pro产品的启动配置文件,利用其中的SplashScreen实现这一需求. 在bin目录下,新建(或编辑)Ar ...

  7. LeetCode721 账户合并

    题解 对于\(vector<vector<string>> accounts\),我们定义\(accounts[i]\)为一个列表项.对于\(accounts\)中的一条列表项 ...

  8. 论文解读《The Philosopher’s Stone: Trojaning Plugins of Large Language Models》

    发表时间:2025 期刊会议:Network and Distributed System Security (NDSS) Symposium 论文单位:Shanghai Jiao Tong Univ ...

  9. 欢迎 PaliGemma 2 – 来自 Google 的新视觉语言模型

    我们很高兴迎来 Google 全新的视觉语言模型 PaliGemma 2,这是 PaliGemma 的一个新版本.与其前代产品一样,PaliGemma 2 使用强大的 SigLIP 进行视觉处理,但在 ...

  10. 中电金信:四川农担X中电金信大数据智能风控平台 护航金融服务乡村振兴

    ​高质量金融服务是乡村振兴的重要支撑.四川省农业融资担保有限公司(以下简称"四川农担")持续探索融资担保服务,努力满足"三农"领域多样化.多层次融资担保需求的同 ...