题解

先用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. oracle 查看临时表空间temp 的使用情况以及扩展表空间

    SELECT D.TABLESPACE_NAME,SPACE "SUM_SPACE(M)",BLOCKS SUM_BLOCKS, USED_SPACE )/SPACE*,) &qu ...

  2. 洛谷 P2376 [USACO09OCT]津贴Allowance 解题报告

    P2376 [USACO09OCT]津贴Allowance 题目描述 作为创造产奶纪录的回报,\(Farmer\) \(John\)决定开始每个星期给\(Bessie\)一点零花钱. \(FJ\)有一 ...

  3. 【CH6201】走廊泼水节

    题目大意:给定一棵树,要求增加若干条边,将其转化为完全图,且该完全图以该树为唯一的最小生成树,求增加的边权最小是多少. 题解:完全图的问题一般要考虑组合计数.重新跑一遍克鲁斯卡尔算法,每次并查集在合并 ...

  4. 缓存面板获取之前页面选中的数据Objuid的方法

    String partUid = request.getParameter("contextInstanceUid"); contextInstanceUid是存在总线总的键名,存 ...

  5. 适用于vue项目的打印插件(转载)

    出处:https://www.cnblogs.com/lvyueyang/p/9847813.html // 使用时请尽量在nickTick中调用此方法 //打印 export default (re ...

  6. bzoj千题计划211:bzoj1996: [Hnoi2010]chorus 合唱队

    http://www.lydsy.com/JudgeOnline/problem.php?id=1996 f[i][j][0/1] 表示已经排出队形中的[i,j],最后一个插入的人在[i,j]的i或j ...

  7. Codeforces Round #477 (rated, Div. 2, based on VK Cup 2018 Round 3) F 构造

    http://codeforces.com/contest/967/problem/F 题目大意: 有n个点,n*(n-1)/2条边的无向图,其中有m条路目前开启(即能走),剩下的都是关闭状态 定义: ...

  8. .NET面试题系列(五)数据结构(Array、List、Queue、Stack)及线程安全问题

    常用数据结构的时间复杂度 如何选择数据结构 Array (T[]) 当元素的数量是固定的,并且需要使用下标时. Linked list (LinkedList<T>) 当元素需要能够在列表 ...

  9. python 喜马拉雅 音乐下载 演示代码

    1.主程序文件 import os import json import requests from contextlib import closing from progressbar import ...

  10. Jquery 较好的效果

    仿google图片效果图片展示相册(jquery)的演示页面 产品相册展示插件slideshow多图可翻页 懒人建站 Jquery分享A Jquery分享B Jquery分享C Jquery分享D