BZOJ 4560 [JLoi2016]字符串覆盖
2017-02-14 08:11
218 查看
贪心+KMP
一副区间DP的样子,然而并不是
如果只有两个串,那我们可以枚举它们的先后顺序。对于maxans则让前一个串在尽量前的位置匹配,后一个串在尽量后的位置匹配。对于minans则枚举前一个串匹配的位置,把后一个串放在第一个串开头后面第一个匹配位置。
推广下去就有了四个串的做法。枚举顺序,对于maxans,第i+1个串的开头要么在第i个串结尾后的第一个匹配位置,要么在第i个串内部的最后一个匹配位置。枚举一下状态即可。对于minans,枚举第2个串的匹配位置,则第一个串一定在第2个串之前的最后面的匹配位置,对于第三个串,要么在第2个串内的最前位置,要么在第2个串后的任意位置。对于后者用后缀Min维护即可。
然后就港了。
一副区间DP的样子,然而并不是
如果只有两个串,那我们可以枚举它们的先后顺序。对于maxans则让前一个串在尽量前的位置匹配,后一个串在尽量后的位置匹配。对于minans则枚举前一个串匹配的位置,把后一个串放在第一个串开头后面第一个匹配位置。
推广下去就有了四个串的做法。枚举顺序,对于maxans,第i+1个串的开头要么在第i个串结尾后的第一个匹配位置,要么在第i个串内部的最后一个匹配位置。枚举一下状态即可。对于minans,枚举第2个串的匹配位置,则第一个串一定在第2个串之前的最后面的匹配位置,对于第三个串,要么在第2个串内的最前位置,要么在第2个串后的任意位置。对于后者用后缀Min维护即可。
然后就港了。
#include<cstdio> #include<cstring> #include<algorithm> #define N 10005 #define cmax(u,v) ((u)<(v)?(u)=(v):0) #define cmin(u,v) ((u)>(v)?(u)=(v):0) using namespace std; namespace runzhe2000 { const int INF = 1<<30; bool mat[5] ; int n, m, len[5], next[5] , h[5], lef[5] , rig[5] , maxans, minans, sufmin ; char str , s[5] ; void KMP_next(char *s, int len, int *next) { next[1] = 0; int p = 0; for(int i = 2; i <= len; i++) { for(; s[p+1] != s[i] && p; p = next[p]); if(s[p+1] == s[i]) ++p; next[i] = p; } } void KMP_solve(char *s, int len, int *next, bool *mat, int *lef, int *rig) { int p = 0; for(int i = 1; i <= n; i++) { for(; str[i] != s[p+1] && p; p = next[p]); if(str[i] == s[p+1]) p++; if(p == len) { p = next[p]; mat[i-len+1] = 1; } else mat[i-len+1] = 0; } for(int i = n-len+2; i <= n+1; i++) mat[i] = 0; p = 0; for(int i = 0; i <= n+1; i++) lef[i] = p, mat[i] ? p=i : 0; p = 0; for(int i = n+1; i >= 0; i--) rig[i] = p, mat[i] ? p=i : 0; } void dfs_make(int nnow, int l, int r, int sum) { if(nnow > m){cmax(maxans, sum); return;} int now = h[nnow]; int nl, nr; nl = lef[now][r+1]; if(nl >= l && nl > 0) { nr = nl + len[now] - 1; dfs_make(nnow+1, nl, max(nr, r), sum + max(0, len[now] - (r-nl+1))); } nl = rig[now][r]; if(nl > 0) { nr = nl + len[now] - 1; dfs_make(nnow+1, nl, nr, sum + len[now]); } } void dfs_init(int now) { if(now > m) {dfs_make(1,0,0,0);return;} for(int i = 1; i <= m; i++) if(!h[i]) {h[i] = now; dfs_init(now + 1); h[i] = 0;} } void main() { int T; scanf("%d",&T); for(; T--; ) { maxans = 0; minans = INF; memset(h,0,sizeof h); scanf("%s%d",str + 1,&m); n = strlen(str + 1); for(int i = 1; i <= m; i++) { scanf("%s",s[i] + 1); len[i] = strlen(s[i] + 1); KMP_next(s[i], len[i], next[i]); KMP_solve(s[i], len[i], next[i], mat[i], lef[i], rig[i]); } dfs_init(1); if(m == 1) minans = len[1]; else if(m == 2) { for(int i = 1; i <= n; i++) for(int j = 1; j <= 2; j++) if(mat[j][i] && rig[3-j][i-1]) { int tmp = len[j] + len[3-j] - max(0, min(i + len[j] - rig[3-j][i-1], len[3-j])); cmin(minans, tmp); } } else if(m == 3) { for(int i = 1; i <= 3; i++) for(int j = 1; j <= 3; j++) if(i != j) for(int k = 1; k <= 3; k++) if(j != k && i != k) for(int p = 1; p <= n; p++) if(mat[j][p] && lef[i][p+1] && rig[k][p-1]) { int r = p + len[j] - 1, q = lef[i][p+1], g = rig[k][p-1]; int tmp = len[i] + len[j] - max(0, min(r, q+len[i]-1) - p + 1); r = max(r, q+len[i] - 1); tmp = tmp + len[k] - max(0, min(r, g+len[k]-1) - g + 1); cmin(minans, tmp); } } else { for(h[1] = 1; h[1] <= 4; h[1]++) for(h[2] = 1; h[2] <= 4; h[2]++) if(h[1] != h[2]) for(h[3] = 1; h[3] <= 4; h[3]++) if(h[1] != h[3] && h[2]!=h[3]) for(h[4] = 1; h[4] <= 4; h[4]++) if(h[1] != h[4] && h[2] != h[4] && h[3] != h[4]) { int cur = INF; for(int i = n+1; i >= 1; i--) { if(mat[h[3]][i] && rig[h[4]][i-1]) { int p = rig[h[4]][i-1]; int tmp = len[h[3]] + len[h[4]] - max(0, min(i+len[h[3]]-1, p+len[h[4]]-1) - p + 1); cmin(cur, tmp); } sufmin[i] = cur; } for(int i = 1; i <= n; i++) if(mat[h[2]][i] && lef[h[1]][i+1]) { int p = lef[h[1]][i+1], r = max(i+len[h[2]]-1, p+len[h[1]]-1); int tmp = len[h[1]] + len[h[2]] - max(0, min(i+len[h[2]]-1, p+len[h[1]]-1) - i + 1); int q = rig[h[3]][i-1]; if(q <= r) { int ttmp = tmp + len[h[3]] - (min(r, q + len[h[3]] - 1) - q + 1), tr = max(r, q + len[h[3]] - 1); int g = rig[h[4]][q-1]; if(g) { ttmp = ttmp + len[h[4]] - max(0, min(tr, g + len[h[4]] - 1) - g + 1); cmin(minans, ttmp); } } tmp = tmp + sufmin[r+1]; cmin(minans, tmp); } } } printf("%d %d\n",minans, maxans); } } } int main() { runzhe2000::main(); }
相关文章推荐
- BZOJ 4560 [JLOI2016]字符串覆盖
- [BZOJ4560][JLOI2016]字符串覆盖(贪心+DP)
- 【BZOJ4560】[JLoi2016]字符串覆盖 KMP+状压DP
- 【BZOJ】4560: [JLoi2016]字符串覆盖
- bzoj 4565: [Haoi2016]字符合并 (字符串dp)
- [扫描线 set] BZOJ 4561 [JLoi2016]圆的异或并
- 【bzoj4557】【JLOI2016】【侦察守卫】【树形dp】
- 【bzoj4561】【JLOI2016】【圆的异或并】【扫描线+set】
- BZOJ 4002 JLOI 2015 有意义的字符串 数列
- BZOJ 4559: [JLoi2016]成绩比较【计数dp,容斥,组合数
- bzoj4561: [JLoi2016]圆的异或并
- 【BZOJ】4002: [JLOI2015]有意义的字符串
- BZOJ4561: [JLoi2016]圆的异或并 计算几何+treap
- bzoj 4002 [JLOI2015]有意义的字符串 数学
- bzoj 4557: [JLoi2016]侦察守卫 树归
- BZOJ 4557 [JLoi2016]侦察守卫
- BZOJ 4558|JLOI 2016|SHOI 2016|方|容斥原理
- [BZOJ4002]JLOI2015有意义的字符串|矩阵乘法
- BZOJ 4557: [JLoi2016]侦察守卫
- 【bzoj4557】【JLoi2016】【树规】侦察守卫