洛谷P5284 [十二省联考2019]字符串问题 [后缀树]
思路
设\(dp_i\)表示以\(i\)结尾的\(A\)串,能达到的最长长度。
然后发现这显然可以\(i\)往自己控制的\(k\)连边,\(k\)往能匹配的\(j\)连边,就是个最长路,只要建出图来就完事了。
显然可以用数据结构得到两点之间是否有边,于是就获得了40分的好成绩。
考虑优化这个建图,字符串也就那么几个数据结构,那就后缀树吧。
有了后缀树,可以发现\(k\)会向\(k\)所在的节点的子树连边,注意不包括\(k\)自己的节点。
那么自己节点怎么办呢?把在这里的所有串拆开然后按长度排一下序即可。
然后就是用虚点优化,随便搞就好了。
这省选题好像也不难
代码先咕着,下午再写。
uptade:下午由于数组开小狂WA,怒调3小时无果,还因为size(),lower_bound()等函数炸掉而一脸懵逼……
数组就应该能开多大开多大……
代码
#include<bits/stdc++.h>
clock_t t=clock();
namespace my_std{
using namespace std;
#define pii pair<int,int>
#define fir first
#define sec second
#define MP make_pair
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define drep(i,x,y) for (int i=(x);i>=(y);i--)
#define go(x) for (int i=head[x];i;i=edge[i].nxt)
#define templ template<typename T>
#define sz 1204040
typedef long long ll;
typedef double db;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
templ inline T rnd(T l,T r) {return uniform_int_distribution<T>(l,r)(rng);}
templ inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
templ inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
templ inline void read(T& t)
{
t=0;char f=0,ch=getchar();double d=0.1;
while(ch>'9'||ch<'0') f|=(ch=='-'),ch=getchar();
while(ch<='9'&&ch>='0') t=t*10+ch-48,ch=getchar();
if(ch=='.'){ch=getchar();while(ch<='9'&&ch>='0') t+=d*(ch^48),d*=0.1,ch=getchar();}
t=(f?-t:t);
}
template<typename T,typename... Args>inline void read(T& t,Args&... args){read(t); read(args...);}
char __sr[1<<21],__z[20];int __C=-1,__zz=0;
inline void Ot(){fwrite(__sr,1,__C+1,stdout),__C=-1;}
inline void print(register int x)
{
if(__C>1<<20)Ot();if(x<0)__sr[++__C]='-',x=-x;
while(__z[++__zz]=x%10+48,x/=10);
while(__sr[++__C]=__z[__zz],--__zz);__sr[++__C]='\n';
}
void file()
{
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
#endif
}
inline void chktime()
{
#ifndef ONLINE_JUDGE
cout<<(clock()-t)/1000.0<<'\n';
#endif
}
#ifdef mod
ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;return ret;}
ll inv(ll x){return ksm(x,mod-2);}
#else
ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x) if (y&1) ret=ret*x;return ret;}
#endif
// inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std;
char s[sz];
int N,n,m;
int la[sz],ra[sz],lb[sz],rb[sz];
int fa[sz],len[sz],ch[sz][27],cnt=1,lst=1;
int edp[sz];
void insert(int c)
{
int cur=++cnt,p=lst;lst=cur;
len[cur]=len[p]+1;
while (p&&!ch[p][c]) ch[p][c]=cur,p=fa[p];
if (!p) return (void)(fa[cur]=1);
int q=ch[p][c];
if (len[p]+1==len[q]) return (void)(fa[cur]=q);
int t=++cnt;
memcpy(ch[t],ch[q],sizeof(ch[q]));
len[t]=len[p]+1;fa[t]=fa[q];
while (p!=-1&&ch[p][c]==q) ch[p][c]=t,p=fa[p];
fa[q]=fa[cur]=t;
}
void calcEndPos(){int x=1;drep(i,N,1) x=ch[x][s[i]-'a'+1],edp[i]=x;}
struct hh{int t,nxt;}edge[sz];
int head[sz],ecnt;
void make_edge(int f,int t){edge[++ecnt]=(hh){t,head[f]};head[f]=ecnt;}
int Fa[sz][25];
void dfs1(int x,int fa){Fa[x][0]=fa;rep(i,1,20) Fa[x][i]=Fa[Fa[x][i-1]][i-1];go(x) dfs1(edge[i].t,x);}
vector<pii>va[sz],vb[sz];
void ins(int id,int lenth,int p)
{
drep(i,20,0) if (Fa[p][i]&&len[Fa[p][i]]>=lenth) p=Fa[p][i];
if (id<=n) va[p].push_back(MP(lenth,id));
else vb[p].push_back(MP(lenth,id));
}
int son[sz],cc;
int deg[sz];
struct hhh{int f,t,w,nxt;}E[sz];
int Head[sz],Ecnt;
void MakeEdge(int f,int t,int w){++deg[t];E[++Ecnt]=(hhh){f,t,w,Head[f]};Head[f]=Ecnt;}
int lastt=0;
void dfs2(int x)
{
sort(va[x].begin(),va[x].end());
int nxt=cc+1,las;cc+=va[x].size()+1;las=cc;
drep(i,(int)va[x].size()-1,0) MakeEdge(nxt+i,nxt+i+1,0),MakeEdge(nxt+i,va[x][i].sec,va[x][i].fir);
rep(i,0,(int)vb[x].size()-1)
{
int pos=lower_bound(va[x].begin(),va[x].end(),MP(vb[x][i].fir,-1))-va[x].begin();
MakeEdge(vb[x][i].sec,nxt+pos,0);
}
go(x) dfs2(edge[i].t),MakeEdge(las,son[edge[i].t],0);
son[x]=nxt;
}
ll dp[sz];
bool vis[sz];
void work()
{
cin>>(s+1);
N=strlen(s+1);
drep(i,N,1) insert(s[i]-'a'+1);
calcEndPos();
rep(i,2,cnt) make_edge(fa[i],i);
dfs1(1,0);
int K,x,y;
read(n);
rep(i,1,n) read(la[i],ra[i]),ins(i,ra[i]-la[i]+1,edp[la[i]]),dp[i]=ra[i]-la[i]+1;
read(m);
rep(i,1,m) read(lb[i],rb[i]),ins(i+n,rb[i]-lb[i]+1,edp[lb[i]]);
read(K);
while (K--) read(x,y),MakeEdge(x,y+n,0);
cc=n+m;
dfs2(1);
queue<int>q;
ll ans=0;
rep(i,1,cc) if (!deg[i]) q.push(i);
while (!q.empty())
{
int x=q.front();q.pop();vis[x]=1;
chkmax(ans,dp[x]);
for (int i=Head[x];i;i=E[i].nxt)
{
int v=E[i].t;--deg[v];chkmax(dp[v],dp[x]+E[i].w);
if (!deg[v]) q.push(v);
}
}
bool flg=1;
rep(i,1,cc) flg&=vis[i];
printf("%lld\n",flg?ans:-1ll);
rep(i,1,N) s[i]='\0',edp[i]=0;
rep(i,1,n) la[i]=ra[i]=0;
rep(i,1,m) lb[i]=rb[i]=0;
rep(i,1,cnt) { fa[i]=len[i]=head[i]=0; rep(j,1,26) ch[i][j]=0; }
rep(i,1,cc) Head[i]=0,va[i].clear(),vb[i].clear(),son[i]=0,deg[i]=0,dp[i]=0,vis[i]=0;
ecnt=cc=Ecnt=0;cnt=lst=1;
}
int main()
{
file();
int T;read(T);
while (T--) work();
return 0;
}
洛谷P5284 [十二省联考2019]字符串问题 [后缀树]的更多相关文章
- 洛谷.5284.[十二省联考2019]字符串问题(后缀自动机 拓扑 DP)
LOJ BZOJ 洛谷 对这题无话可说,确实比较...裸... 像dls说的拿拓扑和parent树一套就能出出来了... 另外表示BZOJ Rank1 tql... 暴力的话,由每个\(A_i\)向它 ...
- 洛谷P5284 [十二省联考2019]字符串问题(SAM+倍增+最长路)
题面 传送门 题解 首先,我们把串反过来,那么前缀就变成后缀,建一个\(SAM\).我们发现一个节点的后缀是它的所有祖先 那么我们是不是直接按着\(parent\)树建边就可以了呢? 显然不是.我们假 ...
- [十二省联考2019]字符串问题——后缀自动机+parent树优化建图+拓扑序DP+倍增
题目链接: [十二省联考2019]字符串问题 首先考虑最暴力的做法就是对于每个$B$串存一下它是哪些$A$串的前缀,然后按每组支配关系连边,做一遍拓扑序DP即可. 但即使忽略判断前缀的时间,光是连边的 ...
- 洛谷.5283.[十二省联考2019]异或粽子(可持久化Trie 堆)
LOJ 洛谷 考场上都拍上了,8:50才发现我读错了题=-= 两天都读错题...醉惹... \(Solution1\) 先求一遍前缀异或和. 假设左端点是\(i\),那么我们要在\([i,n]\)中找 ...
- 洛谷P5289 [十二省联考2019]皮配(01背包)
啊啊啊边界判错了搞死我了QAQ 这题是一个想起来很休闲写起来很恶心的背包 对于\(k=0\)的情况,可以发现选阵营和选派系是独立的,对选城市选阵营和学校选派系分别跑一遍01背包就行了 对于\(k> ...
- 洛谷 5291 [十二省联考2019]希望(52分)——思路+树形DP
题目:https://www.luogu.org/problemnew/show/P5291 考场上写了 16 分的.不过只得了 4 分. 对于一个救援范围,其中合法的点集也是一个连通块. 2n 枚举 ...
- P5284 [十二省联考2019]字符串问题
这是一道涵盖了字符串.图论.数据结构三个方面的综合大题. 把这道题放在D1T2的人应该拖出去打 前置芝士 首先,您至少要会topsort. 其次,如果您只想拿个暴力分,字符串Hash就足够了:如果您想 ...
- Luogu P5284 [十二省联考2019]字符串问题
好难写的字符串+数据结构问题,写+调了一下午的说 首先理解题意后我们对问题进行转化,对于每个字符串我们用一个点来代表它们,其中\(A\)类串的点权为它们的长度,\(B\)类串的权值为\(0\) 这样我 ...
- 【题解】Luogu P5284 [十二省联考2019]字符串问题
原题传送门 我用sa做的本题 (码量似乎有点大) 先对原串建sa 考虑如何建图: 从大到小枚举长度len 先将height中等于len的两个位置在并查集合并起来,将lst也合并(lst是链表) 再将长 ...
随机推荐
- Asp.Net Core中DI的知识总结
在asp.net core中DI的概念是由这几部分组成的: IServiceCollection,保存IServiceDescriptor实例的列表 IServiceProvider,只有一个方法Ge ...
- hadoop distcp 命令使用指导
1.概述 DistCp(distributed copy)是一款被用于大型集群间/集群内的复制工具. 它使用MapReduce来实现其分布,错误处理和恢复以及报告.它将文件列表和目录扩展为map任务的 ...
- vue配置jquery和bootstarp
jquery: 1.npm install jquery --save-dev 引入jquery. 2.在webpack.base.conf.js中添加如下内容: var webpack = requ ...
- 仿 ELEMENTUI 实现一个简单的 Form 表单
原文:仿 ElmentUI 实现一个 Form 表单 一.目标 ElementUI 中 Form 组件主要有以下 功能 / 模块: Form FormItem Input 表单验证 在这套组件中,有 ...
- 基于Vue cli生成的Vue项目的webpack4升级
前面的话 本文将详细介绍从webpack3到webpack4的升级过程 概述 相比于webpack3,webpack4可以零配置运行,打包速度比之前提高了90%,可以直接到ES6的代码进行无用代码剔除 ...
- 使用elementUI滚动条之横向滚动
用过elementUI组件应该会知道它内置一个滚动效果,官网对此组件没有相关文档,也是细心网友发现的. <el-scrollbar></el-scrollbar> 将会出现滚动 ...
- java获取文件行数
public long getLineNumber(File file) { if (file.exists()) { try { FileReader fileReader = new FileRe ...
- Python 实现 Html 转 Markdown(支持 MathJax 数学公式)
因为需要转 html 到 markdown,找了个 python 的库,该库主要是利用正则表达式实现将 Html 转为 Markdown. 数学公式需要自己修改代码来处理. 我 fork 的项目地址: ...
- MySQL物理备份 lvm-snapshot
MySQL备份之 lvm-snapshot lvm-snapshot(工具备份) 优点: 几乎是热备(穿件快照前把表上锁,创建完成后立即释放) 支持所有引擎 备份速度快 无需使用昂贵的商业软件(它是操 ...
- jupyter nootbook本地使用指南
本地文件读入jupyter notebook 在文件夹内,shift+鼠标右键,出现菜单中选择“”在此处打开命令窗口“”,输入jupyter notebook, 可以把本地文件读入jupyter.