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

分析:这题的一个暴力的方法肯定就是对于每个字符枚举删或者不删,然后选择一种方案即可。在这个蛮力法的后面注意到其实在枚举的时候还是有很多重复计算的,比如前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. Yii源码阅读笔记(二十二)

    Module类,属性的注释和构造函数的注释: <?php /** * @link http://www.yiiframework.com/ * @copyright Copyright (c) ...

  2. Example Microprocessor Register Organizations

    COMPUTER ORGANIZATION AND ARCHITECTURE DESIGNING FOR PERFORMANCE NINTH EDITION

  3. Android 图文数据JSON解析

    数据格式为 {"sid":"737","tts":"http:\/\/news.iciba.com\/admin\/tts\/20 ...

  4. 在eclipse中将SVN项目check下来的正确步骤

    学习下面的方法后再也不用从svncheck到本地后再导入到eclipse里了. 1. 首先Import,在弹出框里选择SVN-从SVN检出项目,然后按照提示一步一步直到选中了目标项目,然后点击next ...

  5. DOM9大节点

    ELEMENT_NODE 1 元素节点 常用 ATTRIBUTE_NODE 2 属性节点 常用 TEXT_NODE 3 文本节点 常用 CDATA_SECTION_NODE 4 CDATA区段   E ...

  6. Inside Flask - globals 全局变量(对象代理)

    Inside Flask - globals 全局变量(对象代理) 框架是一个容器,在框架内编程,一般是要遵守框架的约定和使用模式.通常这样的模式是 IoC,即由框架调用用户的代码,而不是用户调用框架 ...

  7. svn更新报错:svn unable to connect to a repository at url

    出现错误:unable to connect to a repository at url 解决办法1. 右键点击本地副本,TortoiseSVN -> Settings -> Saved ...

  8. iOS,第三方库使用

    1.ASIHttpRequest网络请求库 2.MBProgressHUD指示层库 3.Toast+UIView提示库 4.SDWebImage图片缓存库 5.MGSwipeTableCell单元格侧 ...

  9. oracle重建控制文件

    根据已有数据库创建新的控制文件#数据库必须是mounted或open状态 sql> alter database backup controlfile to trace; 可以使用以下快捷方式找 ...

  10. NFC基础

    本文档描述了在Android执行的基本的NFC技术,它说明了如何发送和接收NDEF消息的形式的NFC数据,并介绍Android框架中支持这些功能的API,对于更高级的主题,包括讨论非NDEF数据相关的 ...