题意:给定一些单词,这些单词必须要是一个目标串的子串,同时给定一些串,这些串不能够出现在目标串中,其余一些串只会带来不同附加值。现在问满足前两者的情况下,要求附加值最大。数据给定一个原始串,现在要求在这些串中删除一些字符,输出在满足要求的情况下删除最少的字符并保证附加值尽可能的大。

分析:这题的一个暴力的方法肯定就是对于每个字符枚举删或者不删,然后选择一种方案即可。在这个蛮力法的后面注意到其实在枚举的时候还是有很多重复计算的,比如前a个字符删除或者不删除某个字符对于后面的选择是一样的,而题目要求拥有所有的必有串,因此可以将所有的必有串建立一个ac自动机,然后根据枚举在ac自动机相应节点(状态)的位置从而避免了纯粹的暴力枚举。在匹配的过程中保证不允许非法串被包含进去,设dp[i][j][k]表示处理到第i个字符时,ac自动机中的状态是j,并且包含必有串的状态压缩之后的值为k的最少操作次数和相应的最大的附加值(具体体现在两个三维数组)。那么枚举i-1所有的状态,就能够根据第i个字符在ac自动机中进行转移。

#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std; const int N = ;
const int inf = 0x3f3f3f3f;
int n;
int sz;
char str[];
int del[][N][<<]; // 记录某一状态下最少的更改次数
int sco[][N][<<]; // 在满足最少次数的情况下最大的得分,优先更改次数减少,其次是得分的最大化 struct Ac_auto {
int ch[N][];
int fail[N];
int sta[N];
int gain[N];
char kill[N]; // 只取0,1两个值
int idx, root;
int newnd() {
memset(ch[idx], , sizeof (ch[idx]));
gain[idx] = sta[idx] = fail[idx] = kill[idx] = ;
return idx++;
}
void init() {
idx = , root = newnd();
}
void insert(char ss[], int val) {
int len = strlen(ss);
int p = root;
for (int i = ; i < len; ++i) {
char c = ss[i]-'a';
if (!ch[p][c]) ch[p][c] = newnd();
p = ch[p][c];
}
// 由于题目中说明了不包括相同的单词,因此只需要等于赋值
if (val == ) sta[p] = << sz;
else if (val == -) kill[p] = ;
else gain[p] = val;
}
void build() { // 构建失败指针,ac自动机的精华
queue<int>q;
for (int i = ; i < ; ++i) {
if (ch[root][i]) {
q.push(ch[root][i]);
}
}
while (!q.empty()) {
int p = q.front();
q.pop();
for (int i = ; i < ; ++i) {
int v = ch[p][i];
int x = fail[p];
if (v) {
q.push(v);
while (x && !ch[x][i]) x = fail[x]; // 选择一个最长的后缀串,使fail指针指向它
fail[v] = ch[x][i]; // 无论有没有指向i的节点,其fail指针会指向0
kill[v] |= kill[fail[v]]; // 如果该字符串之中含有非法的串,那么非法性质会传递过来
sta[v] |= sta[fail[v]]; // 状态也需要传递
gain[v] += gain[fail[v]]; // 传递值
} else {
ch[p][i] = ch[x][i];
}
}
}
}
}; Ac_auto ac; void solve() {
memset(del, 0x3f, sizeof (del)); // 对于删除次数初始化为正无穷大
memset(sco, 0x80, sizeof (sco)); // 对于得分初始化为负无穷大
int cur = , nxt = ;
del[cur][][] = ; // 初始化没有字符时不包含任何合法和非法的状态的最少更改字符数为0
sco[cur][][] = ; // 配套的获得的价值为0
int len = strlen(str);
int lim = << sz;
const int &idx = ac.idx;
for (int i = ; i < len; ++i) { // i表示匹配到了那个字符
int c = str[i]-'a';
memset(del[nxt], 0x3f, sizeof (del[nxt]));
memset(sco[nxt], 0x80, sizeof (sco[nxt]));
for (int j = ; j < idx; ++j) { // j记录在ac自动机中匹配到的位置
for (int k = ; k < lim; ++k) { // k表示压缩后的包含必须子串的情况
if (del[cur][j][k] == inf) continue; // 如果这个状态没有计算过,其也就无法转移到新的状态
// 如果删除该字符
if (del[nxt][j][k] > del[cur][j][k] + ) {
del[nxt][j][k] = del[cur][j][k] + ;
sco[nxt][j][k] = sco[cur][j][k];
} else if (del[nxt][j][k] == del[cur][j][k] + ) {
if (sco[nxt][j][k] < sco[cur][j][k]) {
sco[nxt][j][k] = sco[cur][j][k];
}
} // 如果匹配该字符
int np = ac.ch[j][c];
if (ac.kill[np]) continue; // 如果不能够匹配或者该子串不允许被包含
int gain = ac.gain[np];
int nsta = k|ac.sta[np];
if (del[nxt][np][nsta] > del[cur][j][k]) {
del[nxt][np][nsta] = del[cur][j][k];
sco[nxt][np][nsta] = sco[cur][j][k] + gain;
} else if (del[nxt][np][nsta] == del[cur][j][k]) {
if (sco[nxt][np][nsta] < sco[cur][j][k] + gain) {
sco[nxt][np][nsta] = sco[cur][j][k] + gain;
}
}
}
}
swap(cur, nxt);
}
int xdel = inf, xsco;
for (int i = ; i < idx; ++i) {
if (xdel > del[cur][i][lim-]) {
xdel = del[cur][i][lim-];
xsco = sco[cur][i][lim-];
} else if (xdel == del[cur][i][lim-]) {
xsco = max(xsco, sco[cur][i][lim-]);
}
}
if (xdel == inf) {
puts("Banned");
} else {
printf("%d %d\n", xdel, xsco);
}
} int main() {
int T, ca = ;
scanf("%d", &T);
while (T--) {
int val;
sz = ;
ac.init();
scanf("%d", &n);
for (int i = ; i < n; ++i) {
scanf("%s %d", str, &val);
ac.insert(str, val);
if (val == ) ++sz;
}
ac.build();
scanf("%s", str);
printf("Case %d: ", ++ca);
solve();
}
return ;
}

HDU-4534 郑厂长系列故事——新闻净化 AC自动机+DP的更多相关文章

  1. HDU 4539郑厂长系列故事――排兵布阵(状压DP)

    HDU 4539  郑厂长系列故事――排兵布阵 基础的状压DP,首先记录先每一行可取的所哟状态(一行里互不冲突的大概160个状态), 直接套了一个4重循环居然没超时我就呵呵了 //#pragma co ...

  2. HDU 4539 郑厂长系列故事——排兵布阵

    http://acm.hdu.edu.cn/showproblem.php?pid=4539 郑厂长系列故事——排兵布阵 Time Limit: 10000/5000 MS (Java/Others) ...

  3. HDU 4529 郑厂长系列故事——N骑士问题 状压dp

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4529 郑厂长系列故事--N骑士问题 Time Limit: 6000/3000 MS (Java/O ...

  4. HDU 4539 郑厂长系列故事——排兵布阵 状压dp

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4539 郑厂长系列故事--排兵布阵 Time Limit: 10000/5000 MS (Java/O ...

  5. HDU 4539 郑厂长系列故事——排兵布阵 —— 状压DP

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4539 郑厂长系列故事——排兵布阵 Time Limit: 10000/5000 MS (Java/Ot ...

  6. hdu 4524 郑厂长系列故事——逃离迷宫 小水题

    郑厂长系列故事——逃离迷宫 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) To ...

  7. POJ 1185 - 炮兵阵地 & HDU 4539 - 郑厂长系列故事——排兵布阵 - [状压DP]

    印象中这道题好像我曾经肝过,但是没肝出来,现在肝出来了也挺开心的 题目链接:http://poj.org/problem?id=1185 Time Limit: 2000MS Memory Limit ...

  8. HDU 4539 郑厂长系列故事――排兵布阵(曼哈顿距离)

    这虽然是中文题,然而没看懂,不懂的地方,就是在曼哈顿距离这块,网上搜索了一下,写了个程序,是测试曼哈顿距离的. 曼哈顿距离:两点(x1,y1)(x2,y2)的曼哈顿距离为|x1-x2|+|y1-y2| ...

  9. 郑厂长系列故事——体检(hdu 4519)

    郑厂长系列故事--体检 Time Limit: 500/200 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Total S ...

随机推荐

  1. NEC学习 ---- 模块 - 上图下文图文列表

    上图下文图文列表的效果如下图: 可以看到三个红色框中的三中"上图下文的图文列表"; 这里的代码其实没什么问题, 对于这种布局, 其实可以参考我上一篇介绍: NEC学习 ---- 模 ...

  2. 如何使用Jquery自定义命名空间namespace

    // 把生成命名空间的方法绑定在jQuery上 jQuery.namespace = function () { var a = arguments, o = null, i, j, d; for ( ...

  3. 检测PC端和移动端的方法总结(转)

    正在苦逼的实习中,昨天公司让做一个页面,涉及到检测终端的问题,如果是手机设备,就跳转到指定的网页上,以前写响应式布局只要用@media screen来实现布局的差异化适应,但是现在不仅仅是布局,还要针 ...

  4. Windows下mock环境搭建-加速项目Api开发

    本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处! 公司进行技术部拆分,以项目制作为新的开发模式,前端+移动端+后端,于是加速Api开发变得很有必要,准 ...

  5. iOS后台定位,实时向服务器发送最新位置

    第一步,开启后台模式,选中定位,选择project --> capabilities-->Backgorund Modes --> Location updates 如图: Past ...

  6. CentOS7安装配置SAMBA服务器

    假设我们有这样一个场景 共享名 路径 权限 SHAREDOC /smb/docs 所有人员包括来宾均可以访问 RDDOCS /smb/tech 仅允许特定组的用户进行读写访问 特定组的组名为RD,目前 ...

  7. Android内存泄露

    Android 内存泄漏是一个十分头疼的事情.LeakCanary是一款开源软件,主要作用是检测 Android APP 内存泄露.比起以前的 MAT 工具,LeakCanary 有着十分强大的功能, ...

  8. linux的命令

    Linux命令的分类 选项及参数的含义 以"-"引导短格式选项的(单个字符),例如"-l" 以"--"引导长格式选项(多个字符),例如&qu ...

  9. Android中悬浮窗口

    调用WindowManager,并设置WindowManager.LayoutParams的相关属性,通过WindowManager的addView方法创建View,这样产生出来的View根据Wind ...

  10. jsp:中文乱码解决

    说明:request乱码指的是:浏览器向服务器发送的请求参数中包含中文字符,服务器获取到的请求参数的值是乱码: response乱码指的是:服务器向浏览器发送的数据包含中文字符,浏览器中显示的是乱码: ...