LOJ #3049. 「十二省联考 2019」字符串问题
LOJ #3049. 「十二省联考 2019」字符串问题
题意:给你\(na\)个\(A\)类串,\(nb\)个\(B\)类串,\(m\)组支配关系,求一个长度很长的串\(t_1t_2...t_k\)满足
\(t_i\)为\(A\)类串,\(t_i\)能支配一个\(B\)类串,使得该\(B\)类串为\(t_{i+1}\)的前缀。
分析:
- 一个简单的暴力就是枚举\(A_i\)后面能接的\(A_j\)进行连边,然后拓扑序求一下最长路。
- 很难优化,我们发现这相当于在中间塞入一个\(B\)串,然后发现如果答案不是无穷的话,每种\(B\)类串最多只用一次,那么我们可以对于每个支配关系连边,再由\(B\)串向把它当做前缀的那些\(A\)串连边,跑新图的最长路。
- 对反串建立\(sam\),可以发现\(B\)串向\(parent\)树的一个子树上连边,倍增定位可以做到一个\(log\)。
- 考虑\(B\)串可能大于A串的情况,这样的话就很可能两个串在同一个节点上但长度不同,我们可以对于每个\(A,B\)额外开出一个节点\(p\), \(p\rightarrow A\),\(B\rightarrow p\), \(p\)连一个前缀出来,总结点数是\(6n\)级别的吧。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <bitset>
#include <vector>
#include <iostream>
using namespace std;
typedef long long ll;
#define N 1200050
#define M 5000050
#define db(x) cerr<<#x<<" = "<<x<<endl
char w[N];
int n,la,lb,al[N],ar[N],bl[N],br[N],m,xx[N],yy[N];
int head[N],to[M],nxt[M],cnt,Q[N],du[N],tot,rt;
int ch[N][26],fa[N],len[N],uuz,pos[N],lst=1,f[21][N],ln[N],Lst[N];
ll g[N];
bool cmp(const int &x,const int &y) {
return ln[x]==ln[y]?x<y:ln[x]>ln[y];
}
vector<int>V[N];
inline void add(int u,int v) {
to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; du[v]++;
}
void insert(int x,int id) {
int p=lst,np=++uuz,q,nq;
len[np]=len[p]+1; lst=np;
for(;p&&!ch[p][x];p=fa[p]) ch[p][x]=np;
if(!p) fa[np]=rt;
else {
q=ch[p][x];
if(len[q]==len[p]+1) fa[np]=q;
else {
nq=++uuz;
fa[nq]=fa[q];
len[nq]=len[p]+1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[q]=fa[np]=nq;
for(;p&&ch[p][x]==q;p=fa[p]) ch[p][x]=nq;
}
}
}
void dfs(int x) {
int i;
for(i=1;(1<<i)<=uuz;i++) f[i][x]=f[i-1][f[i-1][x]];
for(i=head[x];i;i=nxt[i]) {
f[0][to[i]]=x;
dfs(to[i]);
}
}
int find(int l,int r) {
int p=pos[r];
int i;
for(i=20;i>=0;i--) if(f[i][p]&&len[f[i][p]]>=r-l+1) p=f[i][p];
return p;
}
void solve() {
scanf("%s",w+1);
n=strlen(w+1);
reverse(w+1,w+n+1);
int i,j;
ll ans=0;
scanf("%d",&la);
for(i=1;i<=la;i++) scanf("%d%d",&al[i],&ar[i]);
scanf("%d",&lb);
for(i=1;i<=lb;i++) scanf("%d%d",&bl[i],&br[i]);
scanf("%d",&m);
tot=la+lb;
for(i=1;i<=la;i++) {
al[i]=n-al[i]+1,ar[i]=n-ar[i]+1,swap(al[i],ar[i]);
}
for(i=1;i<=lb;i++) {
bl[i]=n-bl[i]+1,br[i]=n-br[i]+1,swap(bl[i],br[i]);
}
for(i=1;i<=la;i++) ln[i]=ar[i]-al[i]+1;
for(i=1;i<=lb;i++) ln[i+la]=br[i]-bl[i]+1;
rt=tot+1;lst=tot+1;uuz=tot+1;
for(i=1;i<=n;i++) insert(w[i]-'a',i),pos[i]=lst;
for(i=rt+1;i<=uuz;i++) add(fa[i],i);
dfs(rt);
for(i=rt;i<=uuz;i++) head[i]=0,du[i]=0;
cnt=0;
for(i=1;i<=m;i++) {
scanf("%d%d",&xx[i],&yy[i]);
add(xx[i],yy[i]+la);
}
for(i=1;i<=la;i++) {
int p=find(al[i],ar[i]);
V[p].push_back(i);
}
for(i=1;i<=lb;i++) {
int p=find(bl[i],br[i]);
V[p].push_back(i+la);
}
int ee=uuz;
for(i=rt+1;i<=uuz;i++) {
sort(V[i].begin(),V[i].end(),cmp);
int lim=V[i].size(),lst=i;
Lst[i]=i;
if(lim==0) continue;
for(j=0;j<lim;j++) {
ee++;
add(ee,lst);
lst=ee;
if(V[i][j]<=la) add(ee,V[i][j]);
else add(V[i][j],ee);
}
Lst[i]=lst;
}
for(i=rt+1;i<=uuz;i++) add(fa[i],Lst[i]);
uuz=ee;
int l=0,r=0;
for(i=1;i<=uuz;i++) if(!du[i]) Q[r++]=i;
while(l<r) {
int x=Q[l++];
g[x]+=(x<=la?(ar[x]-al[x]+1):0);
ans=max(ans,g[x]);
for(i=head[x];i;i=nxt[i]) {
du[to[i]]--; g[to[i]]=max(g[to[i]],g[x]);
if(!du[to[i]]) Q[r++]=to[i];
}
}
if(r!=uuz)
puts("-1");
else
printf("%lld\n",ans);
cnt=0;
for(i=1;i<=n;i++) pos[i]=0;
for(i=1;i<=uuz;i++) {
fa[i]=len[i]=head[i]=du[i]=g[i]=Q[i]=0; V[i].clear();
}
for(i=0;(1<<i)<=uuz;i++) for(j=rt;j<=uuz;j++) f[i][j]=0;
for(i=rt;i<=uuz;i++) memset(ch[i],0,sizeof(ch[i]));
return ;
}
int main() {
int T;
scanf("%d",&T);
while(T--) solve();
}
LOJ #3049. 「十二省联考 2019」字符串问题的更多相关文章
- 「十二省联考 2019」字符串问题——SAM+DAG
题目 [题目描述] Yazid 和 Tiffany 喜欢字符串问题.在这里,我们将给你介绍一些关于字符串的基本概念. 对于一个字符串 $S$, 我们定义 $\lvert S\rvert$ 表示 $S$ ...
- LOJ 3049: 洛谷 P5284: 「十二省联考 2019」字符串问题
题目传送门:LOJ #3049. 题意简述: 给定一个长度为 \(n\) 的母串 \(S\). 有 \(n_a\) 个 A 类串,都是 \(S\) 的子串,以区间的形式给出. 有 \(n_b\) 个 ...
- 【LOJ 3049】「十二省联考 2019」字符串问题
这个D1T2绝对有毒... 首先我们构造一把反串的后缀自动机. 然后我们就需要找到每一个子串在SAM上的节点. 这个可以通过扫描线+树上倍增处理. 首先我们把所有的子串按照左端点排序, 然后从右往左扫 ...
- LOJ#3048. 「十二省联考 2019」异或粽子 Trie
原文链接www.cnblogs.com/zhouzhendong/p/LOJ3048.html 题解 $O(n\log^2 {a_i})$ 的做法比较简单: 1. 求出第 k 大的是什么: 二分答案, ...
- LOJ#3052. 「十二省联考 2019」春节十二响(启发式合并)
题面 传送门 题解 先考虑一条链的情况,对于\(1\)号点来说,肯定是左子树中最大值和右子树中最大值一组,左子树中次大值和右子树中次大值一组--以此类推 那么如果不是一条链呢?我们把所有的链合并起来就 ...
- LOJ#3048. 「十二省联考 2019」异或粽子(trie树+堆)
题面 传送门 题解 我们先把它给前缀异或和一下,然后就是要求前\(k\)大的\(a_i\oplus a_j\).把\(k\)乘上个\(2\),变成前\(2k\)大的\(a_i\oplus a_j\), ...
- 【LOJ】#3051. 「十二省联考 2019」皮配
LOJ#3051. 「十二省联考 2019」皮配 当时我在考场上觉得这题很不可做... 当然,出了考场后再做,我还是没发现学校和城市是可以分开的,导致我还是不会 事实上,若一个城市投靠了某个阵营,学校 ...
- 「ZJOI2019」&「十二省联考 2019」题解索引
「ZJOI2019」&「十二省联考 2019」题解索引 「ZJOI2019」 「ZJOI2019」线段树 「ZJOI2019」Minimax 搜索 「十二省联考 2019」 「十二省联考 20 ...
- 「十二省联考 2019」皮配——dp
题目 [题目描述] #### 题目背景一年一度的综艺节目<中国好码农>又开始了.本季度,好码农由 Yazid.Zayid.小 R.大 R 四位梦想导师坐镇,他们都将组建自己的梦想战队,并率 ...
随机推荐
- PHP 数组遍历 foreach 语法结构
foreach 语法结构用于遍历数组. foreach() PHP foreach() 语法结构用于遍历操作或输出数组,foreach() 仅能用于遍历数组或对象,当试图将其用于其它数据类型或者一个未 ...
- angular之自定义 directive
1,指令的创建至少需要一个带有@Directive装饰器修饰的控制器类.@Directive装饰器指定了一个选择器名称,用于指出与此指令相关联的属性的名字. 2,创建一个highlight.direc ...
- 初识 JVM
发展历史 1996年,SUN JDK 1.0 Classic VM 发布,纯解释运行,使用外挂进行JIT 1997年 JDK1.1 发布.包含了:AWT.内部类.JDBC.RMI.反射 1998年 J ...
- atom的初次尝试,activate-power-mode 插件和做gif
编辑器是github 和sublime 的综合,作为一个经常逛github的人,还很喜欢sublime的开发,还有什么好不尝试的理由呢. 好吧,我承认,编辑器有很多,但是像它那样炫酷的很少,作为喜欢一 ...
- Linux命令详解-touch
linux的touch命令不常用,一般在使用make的时候可能会用到,用来修改文件时间戳,或者新建一个不存在的文件. 1.命令格式: touch [选项]... 文件... 2.命令参数: -a 或- ...
- 为什么MVC不是一种设计模式?
引用一段话: GoF (Gang of Four,四人组, <Design Patterns: Elements of Reusable Object-Oriented Software> ...
- 【Python】偏函数
此文转载自廖雪峰. Python的functools模块提供了很多有用的功能,其中一个就是偏函数(Partial function).要注意,这里的偏函数和数学意义上的偏函数不一样. 在介绍函数参数的 ...
- C# 设计模式巩固 - 简单工厂模式
前言 设计模式的文章很多.鄙人不才文笔也不咋地.写这篇只为巩固下基础知识,万一不小心帮到了您,是我莫大的荣幸!写的不好欢迎码友指正,废话结束开始进入正题. 介绍 - 简单工厂模式 官方定义:(尴尬~貌 ...
- LINUX中文件描述符传递
body, table{font-family: 微软雅黑; font-size: 10pt} table{border-collapse: collapse; border: solid gray; ...
- python装饰器中functools.wraps的作用详解
直接上代码看效果: # 定义一个最简单的装饰器 def user_login_data(f): def wrapper(*args, **kwargs): return f(*args, **kwar ...