先用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. vue去除地址栏上的'#'号

    const router = new VueRouter({ routes:[], mode :"history"//除去#号 }

  2. virtualenv搭建虚拟环境

    最近因为项目需要,要在CentOS 7 上搭建一套开发环境,虽说Python的背后有着庞大的开源社区支持,但是有一个缺点就是每个包的质量都参差不齐,如果我们在工作服务器上去测试安装每个包,就会造成整个 ...

  3. 深入理解C指针----学习笔记

      深入理解C指针     第1章 认识指针   理解指针的关键在于理解C程序如何管理内存,指针包含的就是内存地址.     1.1 指针和内存   C程序在编译后,以三种方式使用内存: 1. 静态. ...

  4. Java从零到企业级电商项目实战

    欢迎关注我的微信公众号:"Java面试通关手册"(坚持原创,分享各种Java学习资源,面试题,优质文章,以及企业级Java实战项目回复关键字免费领取)回复关键字:"电商项 ...

  5. 新一代的USB 3.0传输规格

    通用序列总线(USB) 从1996问世以来,一统个人电脑外部连接界面,且延伸至各式消费性产品,早已成为现代人生活的一部分.2000年发表的USB 2.0 High-speed规格,提供了480Mbps ...

  6. linux设备驱动模型-浅析-转

    1.  typeof typeof并非ISO C的关键字,而是gcc对C的一个扩展.typeof是一个关键字(类似sizeof),用于获取一个表达式的类型. 举个简单的例子: char tt; typ ...

  7. MySQL之——如何添加新数据库到MySQL主从复制列表 【转】

    转自 转载请注明出处:http://blog.csdn.net/l1028386804/article/details/54653691 MySQL主从复制一般情况下我们会设置需要同步的数据库,使用参 ...

  8. MySQL创建相同表和数据命令

    创建和表departments结构和数据一样的表departments_t mysql> create table departments_t like departments; Query O ...

  9. Petrozavodsk Summer Training Camp 2017 Day 9

    Petrozavodsk Summer Training Camp 2017 Day 9 Problem A. Building 题目描述:给出一棵树,在树上取出一条简单路径,使得该路径的最长上升子序 ...

  10. [转载]锁无关的数据结构与Hazard指针——操纵有限的资源

    Lock-Free Data Structures with Hazard Pointers 锁无关的数据结构与Hazard指针----操纵有限的资源 By Andrei Alexandrescu a ...