题目描述

给出 $A$ 串和 $B$ 串,从 $A$ 串中选出至多 $x$ 个互不重合的段,使得它们按照原顺序拼接后能够得到 $B$ 串。求是否可行。多组数据。

$T\le 10$ ,$|A|,|B|\le 10^5$ ,$x\le 100$ 。


题解

后缀数组+倍增RMQ+贪心+dp

设 $f[i][j]$ 表示从 $A$ 串的前 $i$ 个字符中选出 $j$ 段,能够拼出 $B$ 串的最大长度。

那么考虑转移,如果 $i+1$ 不用则 $f[i+1][j]\leftarrow f[i][j]$ ,否则枚举拼的长度 $k$ ,如果 $A_{i+1...i+k}=B_{f[i][j]+1...f[i][j]+k}$ 则 $f[i+k][j+1]\leftarrow f[i][j]+k$ 。

仔细想想后一步可以不用这样处理,可以直接贪心地选择LCP来拼接。因为选择LCP相比不选择,多拼接的一段和前面相连,相当于本身没有占用次数,不会存在更优解。

因此使用后缀数组+倍增RMQ维护LCP,设 $LCP(A_{i+1},B_{f[i][j]+1})=t$ ,则有转移 $f[i+t][j+1]\leftarrow f[i][j]+t$ 。

时间复杂度 $O(T(nx+n\log n))$ 。

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 200010
using namespace std;
int sa[N] , r[N] , ws[N] , wa[N] , wb[N] , rank[N] , height[N] , mn[N][20] , log[N] , f[N][110];
char A[N] , B[N];
void init(int n , int m)
{
int i , j , p , *x = wa , *y = wb;
for(i = 0 ; i < m ; i ++ ) ws[i] = 0;
for(i = 0 ; i < n ; i ++ ) ws[x[i] = r[i]] ++ ;
for(i = 1 ; i < m ; i ++ ) ws[i] += ws[i - 1];
for(i = n - 1 ; ~i ; i -- ) sa[--ws[x[i]]] = i;
for(p = j = 1 ; p < n ; j <<= 1 , m = p)
{
for(p = 0 , i = n - j ; i < n ; i ++ ) y[p ++ ] = i;
for(i = 0 ; i < n ; i ++ ) if(sa[i] - j >= 0) y[p ++ ] = sa[i] - j;
for(i = 0 ; i < m ; i ++ ) ws[i] = 0;
for(i = 0 ; i < n ; i ++ ) ws[x[y[i]]] ++ ;
for(i = 1 ; i < m ; i ++ ) ws[i] += ws[i - 1];
for(i = n - 1 ; ~i ; i -- ) sa[--ws[x[y[i]]]] = y[i];
for(swap(x , y) , x[sa[0]] = 0 , p = i = 1 ; i < n ; i ++ )
{
if(y[sa[i]] == y[sa[i - 1]] && y[sa[i] + j] == y[sa[i - 1] + j]) x[sa[i]] = p - 1;
else x[sa[i]] = p ++ ;
}
}
for(i = 0 ; i < n ; i ++ ) rank[sa[i]] = i;
for(p = i = 0 ; i < n - 1 ; height[rank[i ++ ]] = p)
for(p ? p -- : 0 , j = sa[rank[i] - 1] ; r[i + p] == r[j + p] ; p ++ );
for(i = 1 ; i <= n ; i ++ ) mn[i][0] = height[i];
for(i = 2 ; i <= n ; i ++ ) log[i] = log[i >> 1] + 1;
for(i = 1 ; (1 << i) <= n ; i ++ )
for(j = 1 ; j + (1 << i) + 1 <= n ; j ++ )
mn[j][i] = min(mn[j][i - 1] , mn[j + (1 << (i - 1))][i - 1]);
}
inline int lcp(int p , int q)
{
p = rank[p] , q = rank[q];
if(p > q) swap(p , q);
p ++ ;
int k = log[q - p + 1];
return min(mn[p][k] , mn[q - (1 << k) + 1][k]);
}
int main()
{
int T;
scanf("%d" , &T);
while(T -- )
{
int n , m , k , i , j , t;
scanf("%d%d%d%s%s" , &n , &m , &k , A , B);
for(i = 0 ; i < n ; i ++ ) r[i] = A[i] - 'a' + 1;
for(i = 0 ; i < m ; i ++ ) r[i + n + 1] = B[i] - 'a' + 1;
r[n] = 27 , r[n + m + 1] = 0 , init(n + m + 2 , 28);
memset(f , 0 , sizeof(f));
for(i = 0 ; i < n ; i ++ )
for(j = 0 ; j <= k ; j ++ )
f[i + 1][j] = max(f[i + 1][j] , f[i][j]) , t = lcp(i , f[i][j] + n + 1) , f[i + t][j + 1] = max(f[i + t][j + 1] , f[i][j] + t);
for(i = 1 ; i <= k ; i ++ )
if(f[n][i] == m)
break;
if(i <= k) puts("YES");
else puts("NO");
}
return 0;
}

【bzoj5073】[Lydsy1710月赛]小A的咒语 后缀数组+倍增RMQ+贪心+dp的更多相关文章

  1. [BZOJ5073] [Lydsy1710月赛]小A的咒语 后缀数组+dp+贪心

    题目链接 首先这种题一看就是dp. 设\(dp[i][j]\)表示\(A\)序列中到\(i\)位之前,取了\(j\)段,在\(B\)中的最长的长度. 转移也比较简单 \[ dp[i][j] \to d ...

  2. [BZOJ5073][Lydsy1710月赛]小A的咒语

    bzoj description 你有一个\(A\)串和\(B\)串,你需要判断是否可以在\(A\)串中拆出\(x\)个互不相交的子串,使它们按顺序拼在一起可以组成\(B\)串. \(|A|,|B|\ ...

  3. 5073 [Lydsy1710月赛]小A的咒语

    LINK:[Lydsy1710月赛]小A的咒语 每次给定两个串 要求从a串中选出x段拼成B串 能否做到.T组数据. \(n\leq 100000,m\leq 100000,T\leq 10,x\leq ...

  4. 【bzoj3879】SvT 后缀数组+倍增RMQ+单调栈

    题目描述 (我并不想告诉你题目名字是什么鬼) 有一个长度为n的仅包含小写字母的字符串S,下标范围为[1,n]. 现在有若干组询问,对于每一个询问,我们给出若干个后缀(以其在S中出现的起始位置来表示), ...

  5. 【bzoj4516】[Sdoi2016]生成魔咒 后缀数组+倍增RMQ+STL-set

    题目描述 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示.例如可以将魔咒字符 1.2 拼凑起来形成一个魔咒串 [1,2].一个魔咒串 S 的非空字串被称为魔咒串 S 的生成魔咒. 例如 S=[1,2 ...

  6. 【BZOJ5073】[Lydsy十月月赛]小A的咒语 DP(错解)

    [BZOJ5073][Lydsy十月月赛]小A的咒语 题解:沙茶DP,完全不用后缀数组. 用f[i][j]表示用了A的前i个字符,用了j段,最远能匹配到哪.因为显然我们能匹配到的地方越远越好,所以我们 ...

  7. 【BZOJ3277/3473】串/字符串 后缀数组+二分+RMQ+双指针

    [BZOJ3277]串 Description 字符串是oi界常考的问题.现在给定你n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串(注意包括本身). Inpu ...

  8. hdu 4691 最长的共同前缀 后缀数组 +lcp+rmq

    http://acm.hdu.edu.cn/showproblem.php? pid=4691 去年夏天,更多的学校的种族称号.当时,没有后缀数组 今天将是,事实上,自己的后缀阵列组合rmq或到,但是 ...

  9. UOJ.35.[模板]后缀排序(后缀数组 倍增)

    题目链接 论找到一个好的教程的正确性.. 后缀数组 下标从1编号: //299ms 2560kb #include <cstdio> #include <cstring> #i ...

随机推荐

  1. HDU1863(Kruskal+并查集水题)

    https://cn.vjudge.net/problem/HDU-1863 省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可). ...

  2. 20155301 《网络攻防》 Exp5 MSF基础应用

    20155301 <网络攻防> Exp5 MSF基础应用 基础问题 1.用自己的话解释什么是exploit,payload,encode 答:exploit就是利用一些工具的,用来收集目标 ...

  3. WPF编程,TextBlock中的文字修饰线(上划线,中划线,基线与下划线)的使用方法。

    原文:WPF编程,TextBlock中的文字修饰线(上划线,中划线,基线与下划线)的使用方法. 版权声明:我不生产代码,我只是代码的搬运工. https://blog.csdn.net/qq_4330 ...

  4. python基础学习1-变量定义赋值,屏幕输入输出

    一.变量定义赋值 输入输出屏幕显示 : name = input("input is your name") age =int( input("input is your ...

  5. [CF1010E]Store[kd-tree]

    题意 有一个长方体,不知道它的位置,给出 \(n\) 个一定在长方体内的点和 \(m\) 个一定不在的点,有 \(k\) 次询问,每次询问一个点是否 在.不在.不确定 在长方体内. \(n\leq 1 ...

  6. 设计模式 笔记 装饰模式 Decorator

    //---------------------------15/04/17---------------------------- //Decorator 装饰模式----对象结构型模式 /* 1:意 ...

  7. docker之网络管理

    一.安装网桥管理工具 [root@node03 web]# yum install bridge-utils -y 二.docker网络的4种模式 host模式,使用--net=host指定. con ...

  8. MyBatis最初的程序解读---API

    API详解:            * 线程安全问题出现的条件        (1) 只有单例对象才可能出现线程安全问题        (2) 多线程环境,即多个线程会共享这个单例对象         ...

  9. Loadrunner 面试常见问题

    三大组件: 脚本生成器,录制和调试脚本 . 控制台,设置运行和资源场景 结果分析器,将测试结果数据以不同的图表呈现,便于性能分析 工作原理: 录制:根据不同协议,记录下客户端和服务器二者之间的对话,生 ...

  10. iOS开发面试题整理

    前言 本文借鉴整理了iOS高级开发常见的面试题,并且分博客一一分析,希望能和大家一起进步学习. 欢迎大家关注我的 Github