HDU-4534 郑厂长系列故事——新闻净化 AC自动机+DP
题意:给定一些单词,这些单词必须要是一个目标串的子串,同时给定一些串,这些串不能够出现在目标串中,其余一些串只会带来不同附加值。现在问满足前两者的情况下,要求附加值最大。数据给定一个原始串,现在要求在这些串中删除一些字符,输出在满足要求的情况下删除最少的字符并保证附加值尽可能的大。
分析:这题的一个暴力的方法肯定就是对于每个字符枚举删或者不删,然后选择一种方案即可。在这个蛮力法的后面注意到其实在枚举的时候还是有很多重复计算的,比如前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的更多相关文章
- HDU 4539郑厂长系列故事――排兵布阵(状压DP)
HDU 4539 郑厂长系列故事――排兵布阵 基础的状压DP,首先记录先每一行可取的所哟状态(一行里互不冲突的大概160个状态), 直接套了一个4重循环居然没超时我就呵呵了 //#pragma co ...
- HDU 4539 郑厂长系列故事——排兵布阵
http://acm.hdu.edu.cn/showproblem.php?pid=4539 郑厂长系列故事——排兵布阵 Time Limit: 10000/5000 MS (Java/Others) ...
- HDU 4529 郑厂长系列故事——N骑士问题 状压dp
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4529 郑厂长系列故事--N骑士问题 Time Limit: 6000/3000 MS (Java/O ...
- HDU 4539 郑厂长系列故事——排兵布阵 状压dp
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4539 郑厂长系列故事--排兵布阵 Time Limit: 10000/5000 MS (Java/O ...
- HDU 4539 郑厂长系列故事——排兵布阵 —— 状压DP
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4539 郑厂长系列故事——排兵布阵 Time Limit: 10000/5000 MS (Java/Ot ...
- hdu 4524 郑厂长系列故事——逃离迷宫 小水题
郑厂长系列故事——逃离迷宫 Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others) To ...
- POJ 1185 - 炮兵阵地 & HDU 4539 - 郑厂长系列故事——排兵布阵 - [状压DP]
印象中这道题好像我曾经肝过,但是没肝出来,现在肝出来了也挺开心的 题目链接:http://poj.org/problem?id=1185 Time Limit: 2000MS Memory Limit ...
- HDU 4539 郑厂长系列故事――排兵布阵(曼哈顿距离)
这虽然是中文题,然而没看懂,不懂的地方,就是在曼哈顿距离这块,网上搜索了一下,写了个程序,是测试曼哈顿距离的. 曼哈顿距离:两点(x1,y1)(x2,y2)的曼哈顿距离为|x1-x2|+|y1-y2| ...
- 郑厂长系列故事——体检(hdu 4519)
郑厂长系列故事--体检 Time Limit: 500/200 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)Total S ...
随机推荐
- Codevs 1021 玛丽卡
Codevs 1021 玛丽卡 题目地址:http://codevs.cn/problem/1021/ 题目描述 Description 麦克找了个新女朋友,玛丽卡对他非常恼火并伺机报复. 因为她和他 ...
- win7下用mklink命令解决delphiXE系列占用C盘空间的问题
DelphiXE从2010以后, 安装程序安装完成后都会在ProgramData目录里复制一份安装程序的备份, 随着版本升级安装包越来越大, 占用C盘的空间也就越来越大 虽然可以通过删除的方式删掉, ...
- iOS中集成ijkplayer视频直播框架
ijkplayer 是一款做视频直播的框架, 基于ffmpeg, 支持 Android 和 iOS, 网上也有很多集成说明, 但是个人觉得还是不够详细, 在这里详细的讲一下在 iOS 中如何集成ijk ...
- MySQL 表与字段编码格式报错
MySQL 表与字段编码格式报错 一.数据库,表,字段编码格式都为latin1(iso-8859-1) .当数据保存到数据库后,中文显示乱码. 解决办法: 1.在访问数据库连接串中添加编码格式: &l ...
- 怎样将BigDecimal转换成Int
BigDecimal a=new BigDecimal(12.88); int b=a.intValue(); System.out.println(b);//b=12;
- Nhiberate (一)
严重参考感谢:@wolfy 操作数据库一直都是直接写SQL语句, 接触的ORM框架也不多,新项目要用数据库,数据库访问采用NHibernate. 1. NHibernate 是基于.Net 的针对关系 ...
- request.GetResponse 400错误处理方法
问题描述:在使用request.GetResponse时,如果是400错误,将抛出异常信息,而获取不到返回内容,所以返回的内容只能在catch上面获取,转载于 http://blog.csdn.net ...
- mssql手工注入及绕过术
报错注入: - 例子:http://www.kfgtfcj.xxx.cn/lzygg/Zixun_show.aspx?id=1 [1]首先爆版本:http://www.kfgtfcj.xxx.cn ...
- PHP二维数组提取函数----把不需要的数据剔除
首先说明一些这个函数的应用场景,比如说你得到的数据是个二维数组,里面的很多成员其实是不必要的,比如说api调用后不必要给别人返回一些用不到的垃圾数据吧,如下是代码. <?php /* * del ...
- confluence重置admin密码
复方法: 1. 运行此sql 找到你的管理员帐户: select u.id, u.user_name, u.active from cwd_user u join cwd_membership m o ...