[十二省联考2019]字符串问题——后缀自动机+parent树优化建图+拓扑序DP+倍增
题目链接:
首先考虑最暴力的做法就是对于每个$B$串存一下它是哪些$A$串的前缀,然后按每组支配关系连边,做一遍拓扑序DP即可。
但即使忽略判断前缀的时间,光是连边的时间就会爆炸,显然不能暴力连边。
对于前缀不好解决,可以将字符串翻转然后变成判断是否是后缀。
可以发现对于后缀自动机的$parent$树,每个节点是子树内所有节点的后缀。
那么我们可以利用$parent$树来优化建图过程,将树上每个点向子节点连边。
对于每个$A$串和$B$串在后缀自动机上匹配出对应节点,如果是$A$串就新建节点并将$parent$树上的对应节点连向它,如果是$B$串就新建节点连向$parent$树上的对应节点。
对于$80\%$的数据,因为保证$B$串比$A$串短,所以对于$parent$树上的一个节点既有出点又有入点是合法的($100\%$的部分最后再说)。
但现在只解决了建图的问题,字符串在后缀自动机上匹配的时间复杂度依旧无法保证,如何找到每个$A,B$串对应的节点?
因为$[l,r]$的串一定是$[1,r]$的串的后缀,所以$[l,r]$的串在$parent$树上对应的节点一定是$[1,r]$的串对应节点的祖先,那么我们可以记录一下所有$[1,r]$的串在$parent$树上对应的节点,然后倍增往上跳来找到$[l,r]$对应的节点。
对于$100\%$的数据,不保证$B$串比$A$串短,那么就可能存在一个$B$串比一个$A$串长,但这两个串在$parent$树上对应的节点相同。如果像上述方式连边的话,就会导致这个$B$串能转移到$A$串。
对于这种情况,我们将连在$parent$树上同一点的所有串存起来,按长度从小到大为第一关键字、先$B$串后$A$串为第二关键字排序,将$parent$树上每个点与父节点之间的边拆开,在这两点之间建一串点,分别与排完序的$A,B$串新建点相连,再将这一串点依次相连,这样有了上下制约关系就不会导致上述情况发生了。
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<bitset>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
int len[1200010];
int pre[1200010];
int tr[1200010][26];
int fa[1200010][19];
int num[200010];
int val[1200010];
int head[1200010];
int to[1400010];
int next[1400010];
int cnt;
int last;
int T;
int tot;
char ch[200010];
int na,nb;
int n,m;
int l,r;
int x,y;
int a[200010];
int b[200010];
int d[1200010];
queue<int>q;
int vis[1200010];
ll f[1200010];
int sum;
struct lty
{
int len,num,opt;
lty(){}
lty(int LEN,int NUM,int OPT){len=LEN,num=NUM,opt=OPT;}
bool operator <(lty a)const
{
return len==a.len?num>a.num:len<a.len;
}
};
vector<lty>v[400010];
inline void add(int x,int y)
{
next[++tot]=head[x];
head[x]=tot;
to[tot]=y;
d[y]++;
}
inline void insert(int x,int id)
{
int p=last;
int np=++cnt;
memset(tr[np],0,sizeof(tr[np]));
last=np;
len[np]=len[p]+1;
num[id]=np;
for(;p&&!tr[p][x];p=pre[p])
{
tr[p][x]=np;
}
if(!p)
{
pre[np]=1;
}
else
{
int q=tr[p][x];
if(len[q]==len[p]+1)
{
pre[np]=q;
}
else
{
int nq=++cnt;
memset(tr[nq],0,sizeof(tr[nq]));
len[nq]=len[p]+1;
pre[nq]=pre[q];
memcpy(tr[nq],tr[q],sizeof(tr[q]));
pre[q]=pre[np]=nq;
for(;p&&tr[p][x]==q;p=pre[p])
{
tr[p][x]=nq;
}
}
}
}
inline void build()
{
for(int i=2;i<=cnt;i++)
{
fa[i][0]=pre[i];
}
for(int j=1;j<=18;j++)
{
for(int i=2;i<=cnt;i++)
{
fa[i][j]=fa[fa[i][j-1]][j-1];
}
}
}
inline int ST(int x,int dis)
{
for(int i=18;i>=0;i--)
{
if(len[fa[x][i]]>=dis)
{
x=fa[x][i];
}
}
return x;
}
inline void clear()
{
for(int i=1;i<=sum;i++)
{
v[i].clear();
}
}
inline void solve()
{
scanf("%s",ch+1);
n=strlen(ch+1);
for(int i=1;i<=n;i++)
{
insert(ch[n-i+1]-'a',i);
}
build();
sum=cnt;
scanf("%d",&na);
for(int i=1;i<=na;i++)
{
scanf("%d%d",&l,&r);
a[i]=++cnt;
int p=ST(num[n-l+1],r-l+1);
v[p].push_back(lty(r-l+1,a[i],0));
val[a[i]]=r-l+1;
}
scanf("%d",&nb);
for(int i=1;i<=nb;i++)
{
scanf("%d%d",&l,&r);
b[i]=++cnt;
int p=ST(num[n-l+1],r-l+1);
v[p].push_back(lty(r-l+1,b[i],1));
}
for(int i=2;i<=sum;i++)
{
sort(v[i].begin(),v[i].end());
int sz=v[i].size();
int now=pre[i];
for(int j=0;j<sz;j++)
{
cnt++;
add(now,cnt);
if(!v[i][j].opt)
{
add(cnt,v[i][j].num);
}
else
{
add(v[i][j].num,cnt);
}
now=cnt;
}
add(now,i);
}
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
add(a[x],b[y]);
}
for(int i=1;i<=cnt;i++)
{
f[i]=val[i];
if(!d[i])
{
q.push(i);
vis[i]=1;
}
}
while(!q.empty())
{
int now=q.front();
q.pop();
for(int i=head[now];i;i=next[i])
{
if(f[to[i]]<f[now]+val[to[i]])
{
f[to[i]]=f[now]+val[to[i]];
}
d[to[i]]--;
if(!d[to[i]])
{
q.push(to[i]);
vis[to[i]]=1;
}
}
}
ll ans=0;
for(int i=1;i<=cnt;i++)
{
if(!vis[i])
{
printf("-1\n");
clear();
return;
}
ans=max(ans,f[i]);
}
printf("%lld\n",ans);
clear();
}
inline void init()
{
cnt=last=1,tot=0;
memset(head,0,sizeof(head));
memset(to,0,sizeof(to));
memset(val,0,sizeof(val));
memset(num,0,sizeof(num));
memset(pre,0,sizeof(pre));
memset(tr[1],0,sizeof(tr[1]));
memset(next,0,sizeof(next));
memset(len,0,sizeof(len));
memset(d,0,sizeof(d));
memset(vis,0,sizeof(vis));
memset(f,0,sizeof(f));
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
init();
solve();
}
}
[十二省联考2019]字符串问题——后缀自动机+parent树优化建图+拓扑序DP+倍增的更多相关文章
- 洛谷.5284.[十二省联考2019]字符串问题(后缀自动机 拓扑 DP)
LOJ BZOJ 洛谷 对这题无话可说,确实比较...裸... 像dls说的拿拓扑和parent树一套就能出出来了... 另外表示BZOJ Rank1 tql... 暴力的话,由每个\(A_i\)向它 ...
- 洛谷P5284 [十二省联考2019]字符串问题 [后缀树]
传送门 思路 设\(dp_i\)表示以\(i\)结尾的\(A\)串,能达到的最长长度. 然后发现这显然可以\(i\)往自己控制的\(k\)连边,\(k\)往能匹配的\(j\)连边,就是个最长路,只要建 ...
- BZOJ 5496: [2019省队联测]字符串问题 (后缀数组+主席树优化建图+拓扑排序)
题意 略 分析 考场上写了暴力建图40分溜了-(结果只得了30分) 然后只要优化建边就行了 首先给出的支配关系无法优化,就直接A向它支配的B连边. 考虑B向以B作为前缀的所有A连边,做一遍后缀数组,两 ...
- 【BZOJ5496】[十二省联考2019]字符串问题(后缀树)
[BZOJ5496][十二省联考2019]字符串问题(后缀树) 题面 BZOJ 洛谷 题解 首先显然可以把具有支配关系的串从\(A\)到\(B\)连一条有向边,如果\(B_i\)是\(A_j\)的前缀 ...
- 【BZOJ5495】[十二省联考2019]异或粽子(主席树,贪心)
[BZOJ5495][十二省联考2019]异或粽子(主席树,贪心) 题面 BZOJ 洛谷 题解 这不是送分题吗... 转异或前缀和,构建可持久化\(Trie\). 然后拿一个堆维护每次的最大值,每次如 ...
- P5284 [十二省联考2019]字符串问题
这是一道涵盖了字符串.图论.数据结构三个方面的综合大题. 把这道题放在D1T2的人应该拖出去打 前置芝士 首先,您至少要会topsort. 其次,如果您只想拿个暴力分,字符串Hash就足够了:如果您想 ...
- Luogu P5284 [十二省联考2019]字符串问题
好难写的字符串+数据结构问题,写+调了一下午的说 首先理解题意后我们对问题进行转化,对于每个字符串我们用一个点来代表它们,其中\(A\)类串的点权为它们的长度,\(B\)类串的权值为\(0\) 这样我 ...
- [LOJ3049] [十二省联考 2019] 字符串问题
题目链接 LOJ:https://loj.ac/problem/3049 洛谷:https://www.luogu.org/problemnew/show/P5284 BZOJ:https://www ...
- LOJ3049 [十二省联考2019] 字符串问题 【后缀自动机】【倍增】【拓扑排序】
题目分析: 建出后缀自动机,然后把A串用倍增定位到后缀自动机上,再把B串用倍增定位到后缀自动机上. SAM上每个点上的A串根据长度从小到大排序,建点,依次连边. 再对于SAM上面每个点,连到儿子的边, ...
随机推荐
- jQuery 父iframe与子iframe 相互调用传值
来自:https://blog.csdn.net/wd4871/article/details/50517597 侵删 父页面中的iframe :如下 <iframe name="su ...
- echarts饼图配置模板
var option = { title:{ text:'完成人构成分析--申报', //标题的样式 textSytle:{ //颜色 color : '#FF0000', //粗细 // fontW ...
- JS table内容转成二维数组,支持colspan和rowspan
思路:1.先初始化colspan的数据到数组2.根据rowspan和colspan计算th和td的矩阵二次填充数组 说明:需要引用到第三方库jQuery,table中的th和td行和列跨度必须正确 & ...
- DVWA 黑客攻防演练(二)暴力破解 Brute Froce
暴力破解,简称"爆破".不要以为没人会对一些小站爆破.实现上我以前用 wordpress 搭建一个博客开始就有人对我的站点进行爆破.这是装了 WordfenceWAF 插件后的统计 ...
- ASP.NET Core 入门教程 6、ASP.NET Core MVC 视图布局入门
一.前言 1.本教程主要内容 ASP.NET Core MVC (Razor)视图母版页教程 ASP.NET Core MVC (Razor)带有Section的视图母版页教程 ASP.NET Cor ...
- 第五周课后作业——热门软件创新分析+附加题1&附加题3
鉴于我们寝室都热衷于手游,所以本次热门软件创新分析我就来分析一下几款热门的抽卡型手游. 阴阳师(后文简称YYS)——剧情画风唯美,配音引人入胜 作为网易公司研发的一款3D日式和风回合制游戏,YYS ...
- c/c++ 继承与多态 容器与继承1
问题:类B公有继承类A,类A有虚函数fun,类B覆盖了虚函数fun,有一个std::vector<A>,添加A的对象a,和B的对象b,到这个容器里,然后从vector里取出来,使用对象a. ...
- 我的第一个python web开发框架(25)——定制ORM(一)
在开始编写ORM模块之前,我们需要先对db_helper进行重构,因为ORM最终生成的sql是需要转给db_helper来执行的,所以拥有一个功能完善.健壮的数据库操作类是非常必要的. 这是项目原db ...
- supervisor management kafka zookeeper
# cat kafka.ini [program:kafka] command=/usr/local/kafka/bin/kafka-server-start.sh /usr/local/kafka/ ...
- 使用time+dd测试硬盘读写速度
命令:time dd if=/dev/zero bs=1M count=2048 of=direct_2G 此命令为在当前目录下新建一个2G的文件 Demo如下: 写速度: time dd if= ...