P4022 [CTSC2012]熟悉的文章 题解
简要题意
给定 \(m\) 个模板串和 \(n\) 个匹配串,如果一个字符串是一个模板串的子串且长度不小于 \(L\) 则称其为“熟悉的”,对于每个匹配串,求一个最大的 \(L\),满足将匹配串分割,熟悉的子串的总长度大于原串长度的 \(90\%\)。
题目分析
首先对于 \(L\),如果有更大的 \(L\) 满足了它也一定满足,因此我们首先对其进行二分。
由于跟子串问题相关,且有多个模板串,我们根据模板串建出广义 SAM,分割这种方式有不可在某一位置重复的特点,因此可以考虑对其进行 DP,从前缀开始考虑,一遍 DP 一遍在 SAM 上匹配,求出当前前缀最长熟悉后缀。
设 \(f_i\) 表示割到 \(i\) 的最大熟悉长度,\(len_k\) 表示 SAM 上当前节点的最大长度,则有
\(f_i=\max(f_{i-1},f_j+(i-j)),j\in [i-len_k,i-L]\)
继续观察这个转移方程,由于我们是在 SAM 匹配,失败时往父节点走,\(i-len_k\) 递增,成功时不变,而 \(i-L\) 随 \(i\) 右移,因此决策集合只会往右增长,使用单调队列维护最优决策即可。
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<deque>
#define ll long long
using namespace std;
int tot=1,nex[3000001][2],le[3000001],fa[3000001];
int dp[3000001];
string s;
struct Node{
int last,num;
};
queue<Node> q;
deque<Node> p;
void inserttrie(string s){
int p=1,len=s.length();
for(int i=0;i<len;i++){
int num=s[i]-'0';
if(!nex[p][num]) nex[p][num]=++tot;
p=nex[p][num];
}
}
int insertsam(int last,int num){
int p=last,np=nex[last][num];le[np]=le[p]+1;
p=fa[p];
for(;p && !nex[p][num];p=fa[p]) nex[p][num]=np;
if(!p) fa[np]=1;
else{
int q=nex[p][num];
if(le[q]==le[p]+1) fa[np]=q;
else{
int clone=++tot;le[clone]=le[p]+1;
for(int i=0;i<=1;i++)nex[clone][i]=(le[nex[q][i]]?nex[q][i]:0);
for(;p && nex[p][num]==q;p=fa[p]) nex[p][num]=clone;
fa[clone]=fa[q];fa[q]=fa[np]=clone;
}
}
return np;
}
void build(){
for(int i=0;i<=1;i++) if(nex[1][i]) q.push((Node){1,i});
while(!q.empty()){
int last=q.front().last,num=q.front().num;q.pop();
int cur=insertsam(last,num);
for(int i=0;i<=1;i++) if(nex[cur][i]) q.push((Node){cur,i});
}
}
bool solve(string s,int ans){
int len=s.length(),now=1,lth=0;
for(int i=1;i<=len;i++);
while(p.size()) p.pop_back();
for(int i=0;i<len;i++){
dp[i+1]=dp[i];
int num=s[i]-'0';
while(p.size() && (i+1-ans>=0 && dp[i+1-ans]-i-1+ans>p.front().last)){
p.pop_front();
}
if(i+1-ans>=0) p.push_front((Node){dp[i+1-ans]-i-1+ans,i+1-ans});
while(!nex[now][num]){
now=fa[now];
lth=le[now];
}
if(!now){now=1;lth=0;continue;}
now=nex[now][num];lth++;
while(p.size() && i+1-lth>p.back().num) p.pop_back();
if(p.size())dp[i+1]=max(dp[i+1],p.back().last+i+1);
}
double num=len*1.0/10*9;
if(num<=dp[len]) return true;
else return false;
}
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>s;
inserttrie(s);
}
build();
for(int i=1;i<=n;i++){
cin>>s;
int l=1,r=s.length();
while(l<r){
int mid=(l+r+1)>>1;
if(solve(s,mid)) l=mid;
else r=mid-1;
}
cout<<l<<endl;
}
}
P4022 [CTSC2012]熟悉的文章 题解的更多相关文章
- P4022 [CTSC2012]熟悉的文章
题目 P4022 [CTSC2012]熟悉的文章 题目大意:多个文本串,多个匹配串,我们求\(L\),\(L\)指(匹配串中\(≥L\)长度的子串出现在文本串才为"熟悉",使得匹配 ...
- [CTSC2012]熟悉的文章(后缀自动机+动态规划)
题目描述 阿米巴是小强的好朋友. 在小强眼中,阿米巴是一个作文成绩很高的文艺青年.为了获取考试作文的真谛,小强向阿米巴求教.阿米巴给小强展示了几篇作文,小强觉得这些文章怎么看怎么觉得熟悉,仿佛是某些范 ...
- 【[CTSC2012]熟悉的文章】
题目 好题啊 \(SAM\)+单调队列优化\(dp\) 首先这个\(L\)满足单调性真是非常显然我们可以直接二分 二分之后套一个\(dp\)就好了 设\(dp[i]\)表示到达\(i\)位置熟悉的文章 ...
- [BZOJ2806][CTSC2012]熟悉的文章(Cheat)
bzoj luogu 题目描述 阿米巴是小强的好朋友. 在小强眼中,阿米巴是一个作文成绩很高的文艺青年.为了获取考试作文的真谛,小强向阿米巴求教.阿米巴给小强展示了几篇作文,小强觉得这些文章怎么看怎么 ...
- 题解-CTSC2012 熟悉的文章
Problem bzoj 题目大意:给定多个标准串和一个文本串,全部为01串,如果一个串长度不少于\(L\)且是任意一个标准串的子串,那么它是"熟悉"的.对于文本串\(A\),把\ ...
- [CTSC2012]熟悉的文章 后缀自动机
题面:洛谷 题解: 观察到L是可二分的,因此我们二分L,然后就只需要想办法判断这个L是否可行即可. 因为要尽量使L可行,因此我们需要求出对于给定L,这个串最多能匹配上多少字符. 如果我们可以对每个位置 ...
- CTSC2012 熟悉的文章
传送门 首先很容易想到对于所有的模式串建出广义后缀自动机,之后对于我们每一个要检查的文本串,先在SAM上跑,计算出来每一个位置能匹配到的最远的位置是多少.(就是当前点减去匹配长度) 之后--考虑DP- ...
- Luogu4022 CTSC2012 熟悉的文章 广义SAM、二分答案、单调队列
传送门 先将所有模板串扔进广义SAM.发现作文的\(L0\)具有单调性,即\(L0\)更小不会影响答案,所以二分答案. 假设当前二分的值为\(mid\),将当前的作文放到广义SAM上匹配. 设对于第\ ...
- [CTSC2012]熟悉的文章 (后缀自动机 单调队列)
/* 首先答案显然是具有单调性的, 所以可以二分进行判断 然后当我们二分过后考虑dp来求最长匹配个数, 发现每个点能够转移的地点 肯定是一段区间, 然后这样就能够得到一个log^2算法 至于每个点的匹 ...
- Luogu-4022 [CTSC2012]熟悉的文章
广义后缀自动机+DP 对于作文库建出广义后缀自动机,广义自动机就是在每次添加一个字符串之前把\(last=0\),然后正常添加就好了 对于每个询问串,预处理出每个位置\(i\)能向前匹配的最长长度\( ...
随机推荐
- String、StringBuffer、StringBuilder 的区别?
一. 介绍 String.StringBuffer.StringBuilder: 前言: String.StringBuffer.StringBuilder 均在java.lang包下: String ...
- 你不知道的 HTTP Referer
前言 上周突然发现自己的自己站点的图片全都403了,之前还是好好的,图片咋就全都访问不了呢?由于我每次发文章都是先发了掘金,然后再从掘金拷贝到我自己的站点,这样我就不用在自己的站点去上传图片了,非常方 ...
- Docker使用教程及常用命令
Docker是一个开源的应用容器引擎,允许开发者将应用以及依赖打包到一个可移植的容器中,然后发布到任何流行的Linux机器或Windows上.它非常适用于持续集成与持续交付(CI/CD). 1. 安装 ...
- 基于 ASP.NET 的投票系统
OnlineVoting 基于 ASP.NET 的投票系统 功能页面 登录 注册 首页 投票广场 查看别人发布的投票. 个人中心 个人资料 换头像.修改密码和其他信息. 发布投票 项目地址:https ...
- 记一次MySql灾难性事件
2023年8月8日,本来系一个风和日丽的夏天中的平凡一天,但这种平凡,注定住佢一定唔平凡,唉...现在回忆起都阵阵咁痛!!! 重要嘅事情讲三次,唔好手贱,唔好手贱,唔好手贱 事日,如常上班,本人系一名 ...
- wineqq中接收文件的查看与移动
在Ubuntu等linux系统中安装QQ都需要安装wine支持,而在使用时,会遇到qq接收到的文件无法直接进行操作等问题. 这时,我们发现直接对文件进行复制后,无法在Ubuntu目录中进行粘贴. 其实 ...
- 解析BeanDefinitionRegistry与BeanDefinition合并
本文分享自华为云社区<Spring高手之路12--BeanDefinitionRegistry与BeanDefinition合并解析>,作者:砖业洋__ . 1.什么是BeanDefini ...
- Java将MySQL建表语句转换为SQLite的建表语句
Java将MySQL建表语句转换为SQLite的建表语句 源代码: package com.fxsen.platform.core.util; import java.util.HashMap; im ...
- 利用AI点亮副业变现:5个变现实操案例的启示
整体思维导图: 在这里先分享五个实操案例: 宝宝起名服务 AI科技热点号 头像壁纸号 小说推广号 流量营销号 你们好,我是小梦. 最初我计划撰写一篇关于AI盈利策略的文章,对AI目前的技术走向.应用场 ...
- centos8环境基本优化
centos8环境基本优化 目录 centos8环境基本优化 1.防火墙优化 2.源优化: 方案1.更换阿里源 方案2.使用centos8.5 源 安装epel源 3.ssh连接慢解决 4.关闭公网, ...