题目链接:

[十二省联考2019]字符串问题

首先考虑最暴力的做法就是对于每个$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+倍增的更多相关文章

  1. 洛谷.5284.[十二省联考2019]字符串问题(后缀自动机 拓扑 DP)

    LOJ BZOJ 洛谷 对这题无话可说,确实比较...裸... 像dls说的拿拓扑和parent树一套就能出出来了... 另外表示BZOJ Rank1 tql... 暴力的话,由每个\(A_i\)向它 ...

  2. 洛谷P5284 [十二省联考2019]字符串问题 [后缀树]

    传送门 思路 设\(dp_i\)表示以\(i\)结尾的\(A\)串,能达到的最长长度. 然后发现这显然可以\(i\)往自己控制的\(k\)连边,\(k\)往能匹配的\(j\)连边,就是个最长路,只要建 ...

  3. BZOJ 5496: [2019省队联测]字符串问题 (后缀数组+主席树优化建图+拓扑排序)

    题意 略 分析 考场上写了暴力建图40分溜了-(结果只得了30分) 然后只要优化建边就行了 首先给出的支配关系无法优化,就直接A向它支配的B连边. 考虑B向以B作为前缀的所有A连边,做一遍后缀数组,两 ...

  4. 【BZOJ5496】[十二省联考2019]字符串问题(后缀树)

    [BZOJ5496][十二省联考2019]字符串问题(后缀树) 题面 BZOJ 洛谷 题解 首先显然可以把具有支配关系的串从\(A\)到\(B\)连一条有向边,如果\(B_i\)是\(A_j\)的前缀 ...

  5. 【BZOJ5495】[十二省联考2019]异或粽子(主席树,贪心)

    [BZOJ5495][十二省联考2019]异或粽子(主席树,贪心) 题面 BZOJ 洛谷 题解 这不是送分题吗... 转异或前缀和,构建可持久化\(Trie\). 然后拿一个堆维护每次的最大值,每次如 ...

  6. P5284 [十二省联考2019]字符串问题

    这是一道涵盖了字符串.图论.数据结构三个方面的综合大题. 把这道题放在D1T2的人应该拖出去打 前置芝士 首先,您至少要会topsort. 其次,如果您只想拿个暴力分,字符串Hash就足够了:如果您想 ...

  7. Luogu P5284 [十二省联考2019]字符串问题

    好难写的字符串+数据结构问题,写+调了一下午的说 首先理解题意后我们对问题进行转化,对于每个字符串我们用一个点来代表它们,其中\(A\)类串的点权为它们的长度,\(B\)类串的权值为\(0\) 这样我 ...

  8. [LOJ3049] [十二省联考 2019] 字符串问题

    题目链接 LOJ:https://loj.ac/problem/3049 洛谷:https://www.luogu.org/problemnew/show/P5284 BZOJ:https://www ...

  9. LOJ3049 [十二省联考2019] 字符串问题 【后缀自动机】【倍增】【拓扑排序】

    题目分析: 建出后缀自动机,然后把A串用倍增定位到后缀自动机上,再把B串用倍增定位到后缀自动机上. SAM上每个点上的A串根据长度从小到大排序,建点,依次连边. 再对于SAM上面每个点,连到儿子的边, ...

随机推荐

  1. Python开发爬虫之BeautifulSoup解析网页篇:爬取安居客网站上北京二手房数据

    目标:爬取安居客网站上前10页北京二手房的数据,包括二手房源的名称.价格.几室几厅.大小.建造年份.联系人.地址.标签等. 网址为:https://beijing.anjuke.com/sale/ B ...

  2. join的简单总结

    BAT面试题:现在有T1.T2.T3三个线程,你怎样保证T2在T1执行完后执行,T3在T2执行完后执行? 这个线程问题通常会在第一轮或电话面试阶段被问到,目的是检测你对”join”方法是否熟悉.这个多 ...

  3. 测者的测试技术手册:揭开java method的一个秘密--巨型函数

    揭开java method的一个秘密:巨型函数 相信,很多人都不知道Java的Method的上限为64K.本文将超过这个上限的函数叫做巨型函数. 巨型函数的问题 1.如果代码超过了这个限制,Java编 ...

  4. .net 支付宝接口小小误区

    1.该密匙目测不是私钥,应用官方文档生成的长私钥. 2. 此公钥用的是应用公钥 3.设置支付完成后的通知页面和回调页面 其他的按照官方文档的demo来实现即可

  5. 使用VsCode自带的Emmet语法

    新建html文件,保存之后,输入"!",按Tap(或Enter)键,自动生成HTML结构 标签只要直接输入标签名(不要输入<>),按Tap(或Enter)键自动生成完整 ...

  6. Apollo的Oracle适配改动

    这几天工作需要使用Apollo配置中心.Apollo唯一的依赖是MySQL数据库,然而公司只有Oracle数据库资源.这里有一个Oracle适配改动的分支,但是它是基于0.8.0版本的Apollo.看 ...

  7. LeetCode算法题-Longest Harmonious Subsequence(Java实现)

    这是悦乐书的第270次更新,第284篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第136题(顺位题号是594).我们定义一个和谐数组是一个数组,其最大值和最小值之间的差 ...

  8. Docker: Harbor一些小知识

    镜像文件上传到私有仓库harbor后,镜像的物理存储位置在哪里? 这些信息记录在docker-compose.yml里,通过观察发现 镜像存储在了宿主机的 volumes: - /data/regis ...

  9. Python基础——8错误、调试和测试

    捕捉错误 try: print('try...') r = 10 / int('2') print('result:', r) except ValueError as e: print('Value ...

  10. django-debug-toolbar使用指南

    好久没发新博客,凑个数... django-debug-toolbar 介绍 django-debug-toolbar 是一组可配置的面板,可显示有关当前请求/响应的各种调试信息,并在单击时显示有关面 ...