【bzoj4136】[FJOI2015]带子串包含约束LCS问题
题目描述:
带有子串包含约束的最长公共子序列问题可以具体表述如下。
给定2个长度分别为n和m的序列X和Y,以及一个子串包含约束集S。
S中共有k个字符串S={S1,S2,…,Sk},其中字符串Si的长度为li,1≤i≤k。带有子串包含约束的最长公共子序列问题就是要找出X和Y的包含约束集S中所有字符串为其子串的最长公共子序列。
例如,如果给定的序列X和Y分别为X=actaagacct, Y=gacctacctc,子串包含约束集S={ata, tact},则子序列actacct是X和Y的一个无约束的最长公共子序列,而包含约束集S中所有字符串为其子串的一个最长公共子序列是atact 。
在本题中请特别关注子串与子序列的区别。字符串T=t1…tn的子串是一个形如T’=t1+i…tm+i的字符串,其中,0≤i,m+i≤n。例如,T=abcdefg,则bcd是T 的一个子串,而bce是T的一个子序列,但不是T 的子串。
设计一个算法,找出给定序列X和Y带有子串包含约束S的最长公共子序列。
输入:
第1行中给出正整数n,m,k,m<300, n<300, k<6。n和m分别表示给定序列X和Y的长度。k表示子串包含约束集S中共有k个字符串。
第2行中有k个整数li,0≤li≤300,1≤i≤k,分别表示子串包含约束集S中k个字符串的长度度。
第3行和第4行分别给出序列X和Y 。
接下来k行每行一个字符串Si
输出:
将计算出的X和Y带子串包含约束S的最长公共子序列的长度输出。
样例输入:
10 10 2
3 4
actaagacct
gacctacctc
ata
tact
样例输出:
5
题解:
AC自动机+序列自动机+哈希+记忆化搜索
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue> #ifdef WIN32
#define LL "%I64d"
#else
#define LL "%lld"
#endif #ifdef CT
#define debug(...) printf(__VA_ARGS__)
#define setfile()
#else
#define debug(...)
#define filename ""
#define setfile() freopen(filename".in", "r", stdin); freopen(filename".out", "w", stdout);
#endif #define R register
#define getc() (S == T && (T = (S = B) + fread(B, 1, 1 << 15, stdin), S == T) ? EOF : *S++)
#define dmax(_a, _b) ((_a) > (_b) ? (_a) : (_b))
#define dmin(_a, _b) ((_a) < (_b) ? (_a) : (_b))
#define cmax(_a, _b) (_a < (_b) ? _a = (_b) : 0)
#define cmin(_a, _b) (_a > (_b) ? _a = (_b) : 0)
char B[1 << 15], *S = B, *T = B;
inline int FastIn()
{
R char ch; R int cnt = 0; R bool minus = 0;
while (ch = getc(), (ch < '0' || ch > '9') && ch != '-') ;
ch == '-' ? minus = 1 : cnt = ch - '0';
while (ch = getc(), ch >= '0' && ch <= '9') cnt = cnt * 10 + ch - '0';
return minus ? -cnt : cnt;
}
#define maxn 310
#define maxk 10
#define maxcnt 30010
int sl[maxk], trie[maxcnt][60], fail[maxcnt], t1[maxn][60], t2[maxn][60], len, cnt;
char str1[maxn], str2[maxn], str[maxn];
int end[maxcnt];
inline void Insert(R int pos)
{
R int now = 0;
for (R int i = 1; i <= len; i++)
{
R int c = str[i] - 'A';
if (!trie[now][c]) now = trie[now][c] = ++cnt;
else now = trie[now][c];
}
end[now] |= pos;
}
std::queue<int> q;
inline void ACmach()
{
fail[0] = 0;
for (R int i = 0; i < 60; ++i)
if (trie[0][i]) q.push(trie[0][i]);
while (!q.empty())
{
R int now = q.front(); q.pop(); end[now] |= end[fail[now]];
for (R int i = 0; i < 60; ++i)
if (!trie[now][i]) trie[now][i] = trie[fail[now]][i];
else
{
fail[trie[now][i]] = trie[fail[now]][i];
q.push(trie[now][i]);
}
}
}
#define hashsize 9991023
#define INF 0x7fffffff
struct Hashtable
{
long long v; int dp;
Hashtable *next;
}*last[hashsize], mem[hashsize], *tot = mem;
inline Hashtable *Ha(R int a, R int b, R int now, R int s)
{
R long long key = ((((long long)a<<9|b)<< 11|now)<< 6|s);
for (R Hashtable *pos = last[key % hashsize]; pos; pos = pos -> next) if (pos -> v == key) return pos;
*++tot = (Hashtable){key, 0,last[key % hashsize]};
last[key % hashsize] = tot;
return tot;
}
int full;
int dfs(R int a, R int b, R int now, R int s)
{
s |= end[now];
R Hashtable *key = Ha(a, b, now, s);
if (key -> dp) return key->dp;
R int tmp = (s == full ? 0 : -INF);
for (R int i = 0; i < 60; ++i)
if (t1[a][i] && t2[b][i])
{
R int temp = dfs(t1[a][i], t2[b][i], trie[now][i], s);
cmax(tmp, temp);
}
return key->dp = tmp + 1;
}
int main()
{
R int n, m, k;
scanf("%d %d %d\n", &n, &m, &k);
full = (1 << k) - 1;
for (R int i = 0; i < k; ++i)
scanf("%d ", &sl[i]);
gets(str1 + 1);
gets(str2 + 1);
for (R int i = 0; i < k; ++i)
{
gets(str + 1);
len = sl[i];
Insert(1 << i);
}
ACmach();
memset(t1[n], 0, sizeof(t1[n]));
for (R int i = n; i; --i)
{
memcpy(t1[i - 1], t1[i], sizeof(t1[i]));
t1[i - 1][str1[i] - 'A'] = i;
}
memset(t2[m], 0, sizeof(t2[m]));
for (R int i = m; i; --i)
{
memcpy(t2[i - 1], t2[i], sizeof(t2[i]));
t2[i - 1][str2[i] - 'A'] = i;
}
R int ans = dfs(0, 0, 0, 0) - 1;
printf("%d\n", dmax(ans, 0));
return 0;
}
/*
10 10 2
3 4
actaagacct
gacctacctc
ata
tact
*/
【bzoj4136】[FJOI2015]带子串包含约束LCS问题的更多相关文章
- 「双串最长公共子串」SP1811 LCS - Longest Common Substring
知识点: SAM,SA,单调栈,Hash 原题面 Luogu 来自 poj 的双倍经验 简述 给定两字符串 \(S_1, S_2\),求它们的最长公共子串长度. \(|S_1|,|S_2|\le 2. ...
- SQL 2005 带自增列 带外键约束 数据导入导出
1,生成建表脚本 选中要导的表,点右键-编写表脚本为-create到 ,生成建表脚本 2,建表(在新库),但不建外键关系 不要选中生成外键的那部分代码,只选择建表的代码 3,导数据,用SQL STU ...
- ms sql 带自增列 带外键约束 数据导入导出
1,生成建表脚本 选中要导的表,点右键-编写表脚本为-create到 ,生成建表脚本 2,建表(在新库),但不建外键关系 不要选中生成外键的那部分代码,只选择建表的代码 3,导数据,用SQL STU ...
- bzoj AC倒序
Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...
- C#的泛型的类型参数可以有带参数的构造函数的约束方式吗?
Review后看到标题让我十分羞愧自己语文功底太差,估计...请见谅......我还特地把这句写回开头了...... 问题 前天遇到的一个问题,所以在MSDN发了个问,刚也丰富了下问题,关于泛型的. ...
- LeetCode:Longest Palindromic Substring 最长回文子串
题目链接 Given a string S, find the longest palindromic substring in S. You may assume that the maximum ...
- Oracle数据库五种约束
oracle 数据库 数据表的5个约束类型:1.主键约束2.外键约束3.唯一约束4.检查约束5.非空约束 主键约束:用来唯一标示表中的一个列,一个表中的主键约束只能有一个,但是可以在一个主键约束中包含 ...
- 【ZH奶酪】如何用Python计算最长公共子序列和最长公共子串
1. 什么是最长公共子序列?什么是最长公共子串? 1.1. 最长公共子序列(Longest-Common-Subsequences,LCS) 最长公共子序列(Longest-Common-Subseq ...
- HDU 1503 Advanced Fruits(LCS+记录路径)
http://acm.hdu.edu.cn/showproblem.php?pid=1503 题意: 给出两个串,现在要确定一个尽量短的串,使得该串的子串包含了题目所给的两个串. 思路: 这道题目就是 ...
随机推荐
- 【ABAP系列】SAP ABAP 行列转换的方法
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[ABAP系列]SAP ABAP 行列转换的方法 ...
- java.lang.NoSuchMethodError: org.apache.spark.internal.Logging.$init$(Lorg/apache/spark/internal/Logging;)V
1.sparkML的版本不对应 请参考官网找到对于版本, 比如我的 spark2.3.3 spark MLlib 也是2.3.3
- js文件编码 的坑
- Linux进程状态——top,ps中看到进程状态D,S,Z的含义
在top和ps命令中有一列显示进程状态,分别有如下值: 值 含义 S 进程处于interruptable sleep状态 D 进程处于Uninterruptable sleep状态 R 进程处于运行状 ...
- 配置DHCP中继
本实验模拟企业网络场景.某公司分部的网络由交换机S1和网关路由器R1组成,员工终端PC-1和PC-2都连接在S1上.公司要求分部内所有员工主机的IP地址都通过总部的DHCP服务器自动获取.分部网关路由 ...
- MySQL-快速入门(10)触发器
1.什么是触发器 触发器是与表有关的命名数据库对象.触发器由事件来触发某个操作. 触发器是特殊的存储过程,触发器不需要call语句来调用,也不需要手工启动,只需要确定一个预定义的事件发生的时候,就会被 ...
- javascript中的继承-寄生组合式继承
前文说过,组合继承是javascript最常用的继承模式,不过,它也有自己的不足:组合继承无论在什么情况下,都会调用两次父类构造函数,一次是在创建子类原型的时候,另一次是在子类构造函数内部.子类最终会 ...
- spring循环依赖是怎么解决的?
回答:循环依赖就是循环引用,就是两个或多个Bean相互之间的持有对方,比如CircleA引用CircleB,CircleB引用CircleA,则它们最终反映为一个环. Spring如何解决循环依赖? ...
- C#中的委托和事件(一)——delegate
前言 来说一说委托(delegate)和事件(event),本篇采取的形式是翻译微软Delegate的docs中的重要部分(不要问我为什么微软的docs有中文还要读英文,因为读中文感觉自己有阅读障碍- ...
- C/C++ 内存与指针
内存与指针杂谈 1.指针 1.数组指针 int(*ptr)[n] ()的优先级高,(*ptr)表示ptr是一个指针,指向一个int类型的一维数组,这个数组的长度为n,也可以说ptr的步长就是n.也就是 ...