[BZOJ4560][JLOI2016]字符串覆盖(贪心+DP)
先用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)的更多相关文章
- BZOJ4560 JLOI2016字符串覆盖(kmp+贪心+状压dp+单调队列)
首先kmp求出每个子串能放在哪些位置.接下来的两部分贪心和状压都可以,各取比较方便的. 最大值考虑贪心.考虑枚举子串的左端点出现顺序,在此基础上每个子串的位置肯定都应该尽量靠前,有是否与上个子串有交两 ...
- BZOJ4560 [JLoi2016]字符串覆盖
题意 字符串A有N个子串B1,B2,-,Bn.如果将这n个子串分别放在恰好一个它在A中出现的位置上(子串之间可以重叠) 这样A中的若干字符就被这N个子串覆盖了.问A中能被覆盖字符个数的最小值和最大值. ...
- 【BZOJ4560】[JLoi2016]字符串覆盖 KMP+状压DP
[BZOJ4560][JLoi2016]字符串覆盖 Description 字符串A有N个子串B1,B2,…,Bn.如果将这n个子串分别放在恰好一个它在A中出现的位置上(子串之间可以重叠)这样A中的若 ...
- 并不对劲的bzoj4560:p3269:[JLOI2016]字符串覆盖
题目大意 \(T\)(\(T\leq10\))组询问 每组询问给出一个字符串\(A\)(\(|A|\leq10^4\)),\(n\)(\(n\leq4\))个\(A\)的子串\(B_1,B_2,B_3 ...
- 【BZOJ】4560: [JLoi2016]字符串覆盖
题解 先用kmp求出来一个ed[i][j]表示在母串的第i位是第j个子串的结尾 考虑状压一个二进制位表示这个子串覆盖过没有 对于最大值,记一个dp[S][i]表示子串的使用状况为S,当前为母串的第i位 ...
- 字符串处理/贪心 Codeforces Round #307 (Div. 2) B. ZgukistringZ
题目传送门 /* 题意:任意排列第一个字符串,使得有最多的不覆盖a/b字符串出现 字符串处理/贪心:暴力找到最大能不覆盖的a字符串,然后在b字符串中动态得出最优解 恶心死我了,我最初想输出最多的a,再 ...
- 【BZOJ-3174】拯救小矮人 贪心 + DP
3174: [Tjoi2013]拯救小矮人 Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 686 Solved: 357[Submit][Status ...
- BZOJ_3174_[Tjoi2013]拯救小矮人_贪心+DP
BZOJ_3174_[Tjoi2013]拯救小矮人_贪心+DP Description 一群小矮人掉进了一个很深的陷阱里,由于太矮爬不上来,于是他们决定搭一个人梯.即:一个小矮人站在另一小矮人的 肩膀 ...
- 洛谷P4823 拯救小矮人 [TJOI2013] 贪心+dp
正解:贪心+dp 解题报告: 传送门! 我以前好像碰到过这题的说,,,有可能是做过类似的题qwq? 首先考虑这种显然是dp?就f[i][j]:决策到了地i个人,跑了j个的最大高度,不断更新j的上限就得 ...
随机推荐
- Windows.event
获取鼠标位置 document.getElementById('div').onmousemove = function(e){ //--------Chrome, firefox 支持------- ...
- 【leetcode 简单】第四题 罗马数字转整数
罗马数字包含以下七种字符:I, V, X, L,C,D 和 M. 字符 数值 I 1 V 5 X 10 L 50 C 100 D 500 M 1000 例如, 罗马数字 2 写做 II ,即为两个并列 ...
- PHP非常好用的分页类
分页类: <?php /* * ********************************************* * @类名: page * @参数: $myde_total - 总记 ...
- [006] largest_common_substring
[Description] Given two different strings, find the largest successive common substring. e.g. str1[] ...
- phinx:php数据库迁移
Phinx使你的php app进行数据迁移的过程变得异常轻松,在五分钟之内你就可以安装好Phinx 并进行数据迁移. 特性 使用php代码进行数据迁移 部署模式下迁移 五分钟之内使用 不再担心数据库的 ...
- linux下的僵尸进程处理SIGCHLD信号【转】
转自:http://www.cnblogs.com/wuchanming/p/4020463.html 什么是僵尸进程? 首先内核会释放终止进程(调用了exit系统调用)所使用的所有存储区,关闭所有打 ...
- ubuntu下中文输入法的配置,建议用fcitx
Fcitx [ˈfaɪtɪks] 是一个支持扩展的输入法框架.它有自己维护的三个输入法,拼音,区位和码表:还支持其他引擎,rime 中州韵,google-pinyin,sunpinyin.Fcitx ...
- angular项目中使用angular-material2
Step 1: Install Angular Material and Angular CDK npm install --save @angular/material @angular/cdk n ...
- Python 根据地址获取经纬度及求距离
方法一: 使用Geopy包 : https://github.com/geopy/geopy (仅能精确到城镇,具体街道无结果返回) from geopy.geocoders import Nom ...
- acm专题---键树
题目来源:http://hihocoder.com/problemset/problem/1014?sid=982973 #1014 : Trie树 时间限制:10000ms 单点时限:1000ms ...