题解

先用kmp求出来一个ed[i][j]表示在母串的第i位是第j个子串的结尾

考虑状压一个二进制位表示这个子串覆盖过没有

对于最大值,记一个dp[S][i]表示子串的使用状况为S,当前为母串的第i位,最大覆盖的个数

每次枚举S一个没有的子串j,把目标状态记成S^(1 << j - 1) = T

dp[T][i]可以从dp[T][i - 1]取个max过来,如果i还是当前枚举的子串j能匹配上,那么可以从dp[S][i - len[j]] + len[j]转移

然后就是考虑覆盖的情况,有些时候覆盖的情况并不存在,但是这个时候会比答案小,所以一定会被更新的

转移的方式是

dp[T][i] = max(dp[S][k] + i - k)我们使用单调队列来维护dp[S][k] - k即可

对于最小值,由于上面覆盖不存在的情况会比真正的情况要少,我们dp[S][i]的定义改成子串使用状况为S,i这个位置存在一个匹配串的结尾

转移方法同上,只不过需要额外一个数组记录一下S的前缀最小值

最小值的情况还会出现某个子串是另一个子串的子串,这个时候我们删掉被包含在另一个串里的串,将剩余的串作为目标状态取到min值

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#define fi first
#define se second
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
//#define ivorysi
using namespace std;
typedef long long int64;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {putchar('-');x = -x;}
if(x >= 10) out(x / 10);
putchar('0' + x % 10);
}
char A[10005];
int N,nxt[10005],len[5],L;
char str[5][1005];
int dp[(1 << 4) + 5][10005],sum[10005],que[10005],ql,qr;
bool ed[10005][5],isalone[5]; void Init() {
scanf("%s",A + 1);
read(N);
for(int i = 1 ; i <= N ; ++i) scanf("%s",str[i] + 1);
L = strlen(A + 1);
memset(ed,0,sizeof(ed));memset(isalone,1,sizeof(isalone));
for(int i = 1 ; i <= N ; ++i) len[i] = strlen(str[i] + 1);
for(int i = 1 ; i <= N ; ++i) {
for(int j = 2 ; j <= len[i] ; ++j) {
int p = nxt[j - 1];
while(p && str[i][p + 1] != str[i][j]) p = nxt[p];
if(str[i][p + 1] == str[i][j]) nxt[j] = p + 1;
else nxt[j] = 0;
}
int p = 0;
for(int k = 1 ; k <= L ; ++k) {
while(p && str[i][p + 1] != A[k]) p = nxt[p];
if(str[i][p + 1] == A[k]) ++p;
else p = 0;
if(p == len[i]) {ed[k][i] = 1;p = nxt[p];}
}
for(int j = 1 ; j <= N ; ++j) {
if(len[i] == len[j]) continue;
p = 0;
for(int k = 1 ; k <= len[j] ; ++k) {
while(p && str[i][p + 1] != str[j][k]) p = nxt[p];
if(str[i][p + 1] == str[j][k]) ++p;
else p = 0;
if(p == len[i]) {isalone[i] = 0;break;}
}
}
}
}
void SolveMax() {
memset(dp,0,sizeof(dp));
for(int S = 0 ; S < (1 << N) ; ++S) {
for(int i = 1 ; i <= N ; ++i) {
if(!(S & (1 << i - 1))) {
que[ql = qr = 1] = 0;
int T = S ^ (1 << i - 1);
for(int k = 1 ; k <= L ; ++k) {
while(ql <= qr && que[ql] <= k - len[i]) ++ql;
while(ql <= qr && dp[S][que[qr]] - que[qr] <= dp[S][k] - k) --qr;
que[++qr] = k;
dp[T][k] = max(dp[T][k - 1],dp[T][k]);
if(ed[k][i]) {
dp[T][k] = max(dp[T][k],dp[S][k - len[i]] + len[i]);
if(ql <= qr) dp[T][k] = max(dp[T][k],dp[S][que[ql]] + k - que[ql]);
}
}
}
}
}
out(dp[(1 << N) - 1][L]);enter;
}
void SolveMin() {
memset(dp,0,sizeof(dp));
for(int S = 0 ; S < (1 << N) ; ++S) for(int k = 0 ; k <= L ; ++k) dp[S][k] = L;
dp[0][0] = 0;
for(int S = 0 ; S < (1 << N) ; ++S) {
for(int i = 1 ; i <= N ; ++i) {
if(!(S & (1 << i - 1))) {
que[ql = qr = 1] = 0;
int T = S ^ (1 << i - 1);
sum[0] = dp[S][0];
for(int k = 1 ; k <= L ; ++k) {
while(ql <= qr && que[ql] <= k - len[i]) ++ql;
while(ql <= qr && dp[S][que[qr]] - que[qr] >= dp[S][k] - k) --qr;
que[++qr] = k;
if(ed[k][i]) {
dp[T][k] = min(dp[T][k],sum[k - len[i]] + len[i]);
if(ql <= qr) dp[T][k] = min(dp[T][k],dp[S][que[ql]] + k - que[ql]);
}
sum[k] = min(sum[k - 1],dp[S][k]);
}
}
}
}
int S = 0;
for(int i = 1 ; i <= N ; ++i) if(isalone[i]) S |= (1 << i - 1);
int ans = L;
for(int k = 1 ; k <= L ; ++k) ans = min(ans,dp[S][k]);
out(ans);space;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
int T;
read(T);
while(T--) {Init();SolveMin();SolveMax();}
}

【BZOJ】4560: [JLoi2016]字符串覆盖的更多相关文章

  1. 【BZOJ4560】[JLoi2016]字符串覆盖 KMP+状压DP

    [BZOJ4560][JLoi2016]字符串覆盖 Description 字符串A有N个子串B1,B2,…,Bn.如果将这n个子串分别放在恰好一个它在A中出现的位置上(子串之间可以重叠)这样A中的若 ...

  2. BZOJ4560 [JLoi2016]字符串覆盖

    题意 字符串A有N个子串B1,B2,-,Bn.如果将这n个子串分别放在恰好一个它在A中出现的位置上(子串之间可以重叠) 这样A中的若干字符就被这N个子串覆盖了.问A中能被覆盖字符个数的最小值和最大值. ...

  3. 并不对劲的bzoj4560:p3269:[JLOI2016]字符串覆盖

    题目大意 \(T\)(\(T\leq10\))组询问 每组询问给出一个字符串\(A\)(\(|A|\leq10^4\)),\(n\)(\(n\leq4\))个\(A\)的子串\(B_1,B_2,B_3 ...

  4. [BZOJ4560][JLOI2016]字符串覆盖(贪心+DP)

    先用KMP求出所有可以放的位置,然后两个值分别处理. 最大值: 贪心,4!枚举放的先后位置顺序,2^3枚举相邻两个串是否有交. 若有交,则后一个的起始位置一定是离前一个的结束位置最近的位置,无交也一样 ...

  5. BZOJ4560 JLOI2016字符串覆盖(kmp+贪心+状压dp+单调队列)

    首先kmp求出每个子串能放在哪些位置.接下来的两部分贪心和状压都可以,各取比较方便的. 最大值考虑贪心.考虑枚举子串的左端点出现顺序,在此基础上每个子串的位置肯定都应该尽量靠前,有是否与上个子串有交两 ...

  6. bzoj 4557: [JLoi2016]侦察守卫 树归

    bzoj 4557: [JLoi2016]侦察守卫 设f[x][j]表示覆盖以x为根的子树的所有应该被覆盖的节点,并且以x为根的子树向下j层全部被覆盖的最小代价. 设g[x][j]表示与x距离大于j全 ...

  7. 笔记:iOS字符串的各种用法(字符串插入、字符串覆盖、字符串截取、分割字符串)(别人的代码直接复制过来的,我脸皮有点厚)

    NSString* str=@"hello";//存在代码区,不可变 NSLog(@"%@",str); //1.[字符串插入] NSMutableString ...

  8. iOS字符串的各种用法(字符串插入、字符串覆盖、字符串截取、分割字符串)

    NSString* str=@"hello";//存在代码区,不可变 NSLog(@"%@",str); //1.[字符串插入] NSMutableString ...

  9. 【BZOJ 3473】 字符串 (后缀数组+RMQ+二分 | 广义SAM)

    3473: 字符串 Description 给定n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串? Input 第一行两个整数n,k. 接下来n行每行一个字符串 ...

随机推荐

  1. Maven变量及常见插件配置详解(转)

    一.变量-自定义变量及内置变量 1.自定义变量 <properties> <project.build.name>tools</project.build.name> ...

  2. oracle 查询重复数据并且删除, 只保留一条数据

    数据库操作中,经常会因为导数据造成数据重复,需要进行数据清理,去掉冗余的数据,只保留正确的数据 一:重复数据根据单个字段进行判断 1.首先,查询表中多余的数据,由关键字段(name)来查询. sele ...

  3. os.path.splitext()用法--分离文件名与扩展名

    用法: os.path.splitext(“文件路径”)    分离文件名与扩展名:默认返回(fname,fextension)元组,可做分片操作 例子: import os path_01='E:\ ...

  4. redis添加systemctl服务

    1.编辑systemctl服务配置文件 vim /lib/systemd/system/redis.service 2.内容如下 [Unit]Description=RedisAfter=networ ...

  5. 卸载并安装指定版本Angular CLI

    1.卸载之前的版本 npm uninstall -g @angular/cli 2.清除缓存,确保卸载干净 npm cache clean 3.检查是否卸载干净 输入命令 ng -v 若显示comma ...

  6. CF&&CC百套计划4 Codeforces Round #276 (Div. 1) A. Bits

    http://codeforces.com/contest/484/problem/A 题意: 询问[a,b]中二进制位1最多且最小的数 贪心,假设开始每一位都是1 从高位i开始枚举, 如果当前数&g ...

  7. 阿里云centos7.3安装lamp环境

    参考文档:http://www.jb51.net/article/96649.htm http://m.blog.csdn.net/qq_33813365/article/details/766337 ...

  8. Python 入门基础7 --文件操作

    今日目录: 一.文件处理 1.什么是文件 2.为何用文件 3.如何用文件 4.文件操作 5.常用方法 6.文件内指针的移动 7.with的使用 一.文件处理 1. 什么是文件 文件是操作系统为用户/应 ...

  9. GDB命令

    recursiveDescription 打印view层次结构

  10. 无法在线安装Genymotion Eclipse插件,显示”There are no categoryzed items“

    去掉对“Group items by category"的勾选.