先用KMP求出所有可以放的位置,然后两个值分别处理。

最大值:

贪心,4!枚举放的先后位置顺序,2^3枚举相邻两个串是否有交。

若有交,则后一个的起始位置一定是离前一个的结束位置最近的位置,无交也一样。

最小值:

首先去掉被其它串包含的串,因为肯定可以和其它串放同样的位置。

将所有串从长到短排序方便DP。

f[S][i]表示当前放的串的情况为S,串目前所覆盖到的最后一个位置为i,覆盖的最小总长度是多少,则有:

当最后一个覆盖到i的串位置与其它串不相交时:f[S][i]=min{f[S'][k]}  这个用一个前缀和优化即可。

当相交时:f[S][i]=min(f[S'][j]+i-j) 因为串已经从长到短排好序了所有没有问题。这个用单调队列优化即可。

写的龟速,跑得飞快。

 #include<cstdio>
#include<algorithm>
#include<cstring>
#define mem(a) memset(a,0,sizeof(a))
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
using namespace std; const int N=;
char s[][N],A[N];
bool b[],fl[][N];
int T,n,len,L[],pos[][N],num[],nxt[N],p[],st[],ed[],f[][N],g[][N],q[][N]; void KMP(char S[],char T[],int pos[],int &num,bool fl[]){
int n=strlen(T+),m=strlen(S+),j=; nxt[]=;
rep(i,,m){
while (j && S[j+]!=S[i]) j=nxt[j];
if (S[j+]==S[i]) nxt[i]=++j; else nxt[i]=;
}
j=; num=;
rep(i,,n){
while (j && S[j+]!=T[i]) j=nxt[j];
if (S[j+]==T[i]) j++;
if (j==m) pos[++num]=i-m+,fl[i]=,j=nxt[j];
}
} bool chk(char S[],char T[]){
int n=strlen(T+),m=strlen(S+);
rep(i,,n-m+){
bool flag=;
rep(j,,m) if (S[j]!=T[i+j-]){ flag=; break; }
if (!flag) return ;
}
return ;
} void solve_max(){
rep(i,,n) p[i]=i; int ans=; mem(fl);
do{
for (int S=; S<<<(n-); S++){
int x=pos[p[]][]+L[p[]]-,res=L[p[]]; ans=max(ans,res); bool flag=;
rep(i,,n){
int d=upper_bound(pos[p[i]]+,pos[p[i]]+num[p[i]]+,x)-pos[p[i]];
if (S&(<<(i-))){
if (d<=num[p[i]] && pos[p[i]][d]>x) res+=L[p[i]],x=pos[p[i]][d]+L[p[i]]-;
else{ flag=; break; }
}else{
d--;
if (d && pos[p[i]][d]<=x) res+=L[p[i]]-(x-pos[p[i]][d]+),x=pos[p[i]][d]+L[p[i]]-;
else{ flag=; break; }
}
if (!flag) ans=max(ans,res);
}
}
}while (next_permutation(p+,p+n+));
printf("%d\n",ans);
} void solve_min(){
int S0=(<<n)-;
rep(i,,n-) rep(j,i+,n) if (!b[j] && chk(s[j],s[i])) b[j]=,S0^=<<(j-);
memset(f,0x3f,sizeof(f)); memset(g,0x3f,sizeof(g));
mem(f[]); mem(g[]);
rep(i,,(<<n)-) st[i]=,ed[i]=;
rep(i,,len){
for (int S=; S<<<n; S++){
if (S&(S^S0)) continue; g[S][i]=g[S][i-];
rep(j,,n) if (S&(<<(j-)) && fl[j][i]){
int S1=S^(<<(j-));
if (i-L[j]>=) f[S][i]=min(f[S][i],g[S1][i-L[j]]+L[j]);
while (st[S1]<=ed[S1] && q[S1][st[S1]]<=i-L[j]) st[S1]++;
if (st[S1]<=ed[S1]) f[S][i]=min(f[S][i],f[S1][q[S1][st[S1]]]+i-q[S1][st[S1]]);
while (st[S]<=ed[S] && f[S][q[S][ed[S]]]-q[S][ed[S]]>=f[S][i]-i) ed[S]--;
q[S][++ed[S]]=i; g[S][i]=min(g[S][i-],f[S][i]);
}
}
}
printf("%d ",g[S0][len]);
} int main(){
freopen("bzoj4560.in","r",stdin);
freopen("bzoj4560.out","w",stdout);
for (scanf("%d",&T); T--; ){
mem(fl); mem(b); scanf("%s",A+); len=strlen(A+); scanf("%d",&n);
rep(i,,n) scanf("%s",s[i]+),L[i]=strlen(s[i]+);
rep(i,,n-) rep(j,i+,n) if (L[i]<L[j]) swap(s[i],s[j]),swap(L[i],L[j]);
rep(i,,n) KMP(s[i],A,pos[i],num[i],fl[i]);
solve_min(); solve_max();
}
return ;
}

[BZOJ4560][JLOI2016]字符串覆盖(贪心+DP)的更多相关文章

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

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

  2. BZOJ4560 [JLoi2016]字符串覆盖

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

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

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

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

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

  5. 【BZOJ】4560: [JLoi2016]字符串覆盖

    题解 先用kmp求出来一个ed[i][j]表示在母串的第i位是第j个子串的结尾 考虑状压一个二进制位表示这个子串覆盖过没有 对于最大值,记一个dp[S][i]表示子串的使用状况为S,当前为母串的第i位 ...

  6. 字符串处理/贪心 Codeforces Round #307 (Div. 2) B. ZgukistringZ

    题目传送门 /* 题意:任意排列第一个字符串,使得有最多的不覆盖a/b字符串出现 字符串处理/贪心:暴力找到最大能不覆盖的a字符串,然后在b字符串中动态得出最优解 恶心死我了,我最初想输出最多的a,再 ...

  7. 【BZOJ-3174】拯救小矮人 贪心 + DP

    3174: [Tjoi2013]拯救小矮人 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 686  Solved: 357[Submit][Status ...

  8. BZOJ_3174_[Tjoi2013]拯救小矮人_贪心+DP

    BZOJ_3174_[Tjoi2013]拯救小矮人_贪心+DP Description 一群小矮人掉进了一个很深的陷阱里,由于太矮爬不上来,于是他们决定搭一个人梯.即:一个小矮人站在另一小矮人的 肩膀 ...

  9. 洛谷P4823 拯救小矮人 [TJOI2013] 贪心+dp

    正解:贪心+dp 解题报告: 传送门! 我以前好像碰到过这题的说,,,有可能是做过类似的题qwq? 首先考虑这种显然是dp?就f[i][j]:决策到了地i个人,跑了j个的最大高度,不断更新j的上限就得 ...

随机推荐

  1. 【BZOJ】1066: [SCOI2007]蜥蜴

    [算法]网络流-最大流(dinic) [题解] 构图思路: 因为石柱高度是可以被消耗的,即一根石柱可通过的蜥蜴数量有限,取舍问题中这样表示容量的属性显然可以作为网络流中的边. 于是将一根石柱拆成顶部和 ...

  2. js中字符串和json数组的相互转换

    //示例 var a={"name":"tom","sex":"男","age":"24& ...

  3. PHP做文件限速下载

    <?php include("DBDA.class.php"); $db = new DBDA(); $bs = $_SERVER["QUERY_STRING&qu ...

  4. array_unique() 去重复

    array_unique() 定义和用法 array_unique() 函数移除数组中的重复的值,并返回结果数组. 当几个数组元素的值相等时,只保留第一个元素,其他的元素被删除. 返回的数组中键名不变 ...

  5. VC进度条的使用

    m_progress->GetPos(); //获取进度条的当前位置 m_progress->GetRange(int min,int max); //获取进度条控件的范围的下限和上限 m ...

  6. Lithium中关键特性更新

    Lithium中关键特性更新 1. Lithium特性更新概述 Lithium相对于Helium更新特性共27项,其中原有特性提升或增强13项,新增特性14项,如下表所示 特性类型 相对于Helium ...

  7. python基础之内置异常对象

    前言 什么叫异常?简单来说就是程序运行发生了预计结果之外的情况从而导致程序无法正常运行.而python解释器将一些常见的异常情况在它发生时打包成一个异常对象,我们可以通过捕捉这些异常对象从而进行处理, ...

  8. python并发编程之Queue线程、进程、协程通信(五)

    单线程.多线程之间.进程之间.协程之间很多时候需要协同完成工作,这个时候它们需要进行通讯.或者说为了解耦,普遍采用Queue,生产消费模式. 系列文章 python并发编程之threading线程(一 ...

  9. C++之模板编程

    当我们越来越多的使用C++的特性, 将越来越多的问题和事物抽象成对象时, 我们不难发现:很多对象都具有共性. 比如 数值可以增加.减少:字符串也可以增加减少. 它们的动作是相似的, 只是对象的类型不同 ...

  10. 千万不要运行的 Linux 命令

    本文中列出的命令绝对不可以运行,即使你觉得很好奇也不行,除非你是在虚拟机上运行(出现问题你可以还原),因为它们会实实在在的破坏你的系统.所以不在root等高级管理权限下执行命令是很好的习惯. 本文的目 ...