[BZOJ5073] [Lydsy1710月赛]小A的咒语 后缀数组+dp+贪心
首先这种题一看就是dp。
设\(dp[i][j]\)表示\(A\)序列中到\(i\)位之前,取了\(j\)段,在\(B\)中的最长的长度。
转移也比较简单
dp[i][j] \to dp[i+k][j+1] \quad a[i+1..i+k]=b[dp[i][j]..dp[i][j]+k]
\]
但是这样做的复杂度肯定不行。
发现有一个贪心的思路,因为既然我这里已经占用了一次次数了,那么肯定要尽量地多在B中匹配才好。
所以这里的\(k\)可以直接取到\(LCP(a[i+1],b[dp[i][j]+1])\)。中间的点可以直接跳过,不用转移过去。
#include<bits/stdc++.h>
using namespace std;
#define fec(i,x,y) (int i=head[x],y=g[i].to;i;i=g[i].ne,y=g[i].to)
#define dbg(...) fprintf(stderr,__VA_ARGS__)
#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
#define fi first
#define se second
#define pb push_back
template<typename I>inline void read(I&x){int f=0,c;while(!isdigit(c=getchar()))c=='-'?f=1:0;x=c&15;while(isdigit(c=getchar()))x=(x<<1)+(x<<3)+(c&15);f?x=-x:0;}
template<typename A,typename B>inline char SMAX(A&a,const B&b){return a<b?a=b,1:0;}
template<typename A,typename B>inline char SMIN(A&a,const B&b){return a>b?a=b,1:0;}
typedef long long ll;typedef unsigned long long ull;typedef std::pair<int,int>pii;
const int N=2e5+7,M=100+7,LOG=20;
int T,n,m,p,ans;char a[N],b[N],s[N];
int dp[N][M];
int sa[N],rk[N],sec[N],tax[N],h[N];
inline void Make_SA(char*s,int n){
int m=26,*rnk=rk,*sc=sec;
for(int i=1;i<=m;++i)tax[i]=0;
for(int i=1;i<=n;++i)tax[rnk[i]=s[i]]++;
for(int i=1;i<=m;++i)tax[i]+=tax[i-1];
for(int i=n;i;--i)sa[tax[rnk[i]]--]=i;
for(int k=1;k<=n;k<<=1){
int p=0;
for(int i=n-k+1;i<=n;++i)sc[++p]=i;
for(int i=1;i<=n;++i)if(sa[i]>k)sc[++p]=sa[i]-k;
for(int i=1;i<=m;++i)tax[i]=0;
for(int i=1;i<=n;++i)tax[rnk[sc[i]]]++;
for(int i=1;i<=m;++i)tax[i]+=tax[i-1];
for(int i=n;i;--i)sa[tax[rnk[sc[i]]]--]=sc[i];
swap(rnk,sc);p=rnk[sa[1]]=1;
for(int i=2;i<=n;++i)rnk[sa[i]]=(sc[sa[i]]==sc[sa[i-1]]&&sc[sa[i]+k]==sc[sa[i-1]+k]?p:++p);
if(p>=n)break;else m=p;
}
for(int i=1;i<=n;++i)rk[sa[i]]=i;
}
inline void Make_h(char*s,int n){
for(int i=1,f=0;i<=n;++i){
if(f)f--;int j=sa[rk[i]-1];
while(i+f<=n&&j+f<=n&&s[i+f]==s[j+f])++f;
h[rk[i]]=f;
}
}
int f[N][LOG];
inline void RMQ_init(int n){
for(int i=1;i<=n;++i)f[i][0]=h[i];
for(int j=1;(1<<j)<=n;++j)
for(int i=1;i+(1<<j)-1<=n;++i)
f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
inline int Min(int l,int r){int k=__lg(r-l+1);return min(f[l][k],f[r-(1<<k)+1][k]);}
inline int LCP(int x,int y,int n=::n+m){if(x==y)return n-x+1;x=rk[x],y=rk[y];if(x>y)swap(x,y);return Min(x+1,y);}
inline void DP(){
for(int i=0,k;i<n;++i)
for(int j=0;j<=p;++j)
SMAX(dp[i+1][j],dp[i][j]),
k=min(n-i,LCP(i+1,dp[i][j]+n+1)),
j<p&&SMAX(dp[i+k][j+1],dp[i][j]+k);
}
inline void CSH(){
memset(dp,0,sizeof(dp));
ans=0;
}
int main(){
#ifdef hzhkk
freopen("hkk.in","r",stdin);
#endif
read(T);
while(T--){
CSH();
read(n),read(m),read(p);
scanf("%s%s",a+1,b+1);
for(int i=1;i<=n;++i)s[i]=a[i]-'a'+1;
for(int i=1;i<=m;++i)s[i+n]=b[i]-'a'+1;
Make_SA(s,n+m);Make_h(s,n+m);
RMQ_init(n+m);
DP();
for(int i=1;i<=p;++i)SMAX(ans,dp[n][i]);
if(ans>=m)printf("YES\n");
else printf("NO\n");
}
}
[BZOJ5073] [Lydsy1710月赛]小A的咒语 后缀数组+dp+贪心的更多相关文章
- 【bzoj5073】[Lydsy1710月赛]小A的咒语 后缀数组+倍增RMQ+贪心+dp
题目描述 给出 $A$ 串和 $B$ 串,从 $A$ 串中选出至多 $x$ 个互不重合的段,使得它们按照原顺序拼接后能够得到 $B$ 串.求是否可行.多组数据. $T\le 10$ ,$|A|,|B| ...
- [BZOJ5073][Lydsy1710月赛]小A的咒语
bzoj description 你有一个\(A\)串和\(B\)串,你需要判断是否可以在\(A\)串中拆出\(x\)个互不相交的子串,使它们按顺序拼在一起可以组成\(B\)串. \(|A|,|B|\ ...
- 5073 [Lydsy1710月赛]小A的咒语
LINK:[Lydsy1710月赛]小A的咒语 每次给定两个串 要求从a串中选出x段拼成B串 能否做到.T组数据. \(n\leq 100000,m\leq 100000,T\leq 10,x\leq ...
- 【BZOJ5073】[Lydsy十月月赛]小A的咒语 DP(错解)
[BZOJ5073][Lydsy十月月赛]小A的咒语 题解:沙茶DP,完全不用后缀数组. 用f[i][j]表示用了A的前i个字符,用了j段,最远能匹配到哪.因为显然我们能匹配到的地方越远越好,所以我们 ...
- [bzoj1692][Usaco2007 Dec]队列变换_后缀数组_贪心
队列变换 bzoj-1692 Usaco-2007 Dec 题目大意:给定一个长度为$n$的字符串.每次从头或尾取出一个字符加到另一个字符串里.要求变换后生成的字符串字典序最小,求字典序最小的字符串. ...
- [bzoj4278][ONTAK2015]Tasowanie_后缀数组_贪心
Tasowanie bzoj-4278 ONTAK-2015 题目大意:给定两个字符串,求两个字符串二路归并之后生成的字典序最小的字符串是什么. 注释:$1\le len_1,len_2\le 2\c ...
- [BZOJ 5072][Lydsy1710月赛]小A的树
传送门 \(\color{green}{solution}\) 嗯...其实我也不太会,所以大胆猜个结论吧(后来证了一下,然后放弃了...). 我们发现如果要使一个联通块的黑点数量为\(k\)的方案最 ...
- BZOJ5072:[Lydsy1710月赛]小A的树(树形DP)
Description BZOJ只是扔了个下载链接 Solution 设$f[x][i]$表示$x$点选中$i$个黑点的最小连通块. 设$g[x][i]$表示$x$点选中$i$个黑点的最大连通块. 转 ...
- [BZOJ 5074][Lydsy1710月赛]小B的数字
传送门 \(\color{green}{solution}\) 设 \[b_{i}=2^{w_{i}},sum= \sum_{i=1}^{n}{w_{i}}\] 则对于任意\(a_{i}\)都有 \[ ...
随机推荐
- 让VirtualBox虚拟机实现开机自动后台运行
转至:http://www.cnblogs.com/top5/archive/2012/01/19/2326234.html 测试环境:Host OS: Windows 7 x64 Guest OS: ...
- LNMP环境搭建最好用的两种方法(亲测)
经历了一个PHP服务器项目,手动编译部署PHP,Swoole环境太让人郁闷了,所以尝试过两种不错的方法,分享出来方便同样经历痛苦的coder. 第一种方式: 安装LNMP按照这里的步骤执行,网址戳我 ...
- php面试专题---Mysql索引类型、介绍及优点
php面试专题---Mysql索引类型.介绍及优点 一.总结 一句话总结: 精品视频讲解里面的资料来源也是通过各种资料,比如博客.书等,只不过是基于讲解者的知识体系有整理的过程 1.B-Tree索引三 ...
- day16—正是Github,让社会化编程成为现实。
转行学开发,代码100天——2018-04-01 今天简单了解了一下GitHub的使用. 对于GitHub,在很多年前开始写程序的时候就频繁听到,也早早地注册之后看了真容.但是由于自己一直未产出较大型 ...
- Oracle-创建索引分区
对大数据量索引进行分区同样能够优化应用系统的性能.一般来说,如果索引所对应的表的数据量非常大,比如几百万甚至上千万条数据,则索引也会占用很大的空间,这时,建议对索引进行分区. Oracle索引分区分为 ...
- 死锁(Deadlock)
死锁:是指是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程. ...
- SparkSQL架构
Spark SQL运行架构 Spark SQL由Core.Catalyst.Hive和Hive-Thriftserver组成 core:负责处理数据的输入/输出,从不同的数据源获取数据(如RDD.Pa ...
- C# 加密解密类
一. MD5 1 防止看到明文 数据库密码,加盐(原密码+固定字符串,然后再MD5/双MD5) 2 防篡改 3 急速秒传(第一次上传文件,保存md5摘要,第二次上传检查md5摘要) 4文件 ...
- 【EWM系列】SAP EWM模块-部分流程图
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[EWM系列]SAP EWM模块-部分流程图 ...
- 使EasyUI的window、panel、dialog 不被拖出页面
function easyuiPanelOnMove(left, top) { var l = left; var t = top; if (l < 1) { l = 1; } ...