题目传送门:LOJ #3089

题意简述:

有一个长度为 \(n\) 的母串,其中某些位置已固定,另一些位置可以任意填。

同时给定 \(m\) 个小串,第 \(i\) 个为 \(S_i\),所有位置都已固定,它的价值为 \(V_i\)。

每次每个小串在母串中出现一次,便会给答案的多重集贡献一个 \(V_i\)。

最终的答案为多重集的几何平均数,定义空集的几何平均数为 \(1\)。

请你求出一个合法母串(往可以填的位置填合法字符)使得答案最大。

\(1\le n,s\le 1501\),\(1\le V_i\le \max V=10^9\),其中 \(\displaystyle s=\sum_{i=1}^{m}|S_i|\)。

题解:

假设多重集的大小为 \(c\),第 \(i\) 个元素为 \(w_i\),则 \(\displaystyle\mathrm{Ans}=\sqrt[c]{\prod_{i=1}^{c}w_i}\)。

两边取对数,有 \(\displaystyle\ln\mathrm{Ans}=\frac{1}{c}\sum_{i=1}^{c}\ln w_i\),转化为经典的 0/1 分数规划问题。

二分答案,若等式右边大于 \(\mathrm{mid}\),则有:

\(\begin{aligned}\frac{1}{c}\sum_{i=1}^{c}\ln w_i&>\mathrm{mid}\\\sum_{i=1}^{c}\ln w_i&>c\cdot\mathrm{mid}\\\sum_{i=1}^{c}(\ln w_i-\mathrm{mid})&>0\end{aligned}\)

所以,建出小串的 AC 自动机,然后二分答案后在 AC 自动机上 DP 判断不等式是否满足。

DP 时每个小串的权值设为 \(\ln V_i-\mathrm{mid}\),注意要记录最佳转移点,以输出方案。

下面是代码,复杂度 \(\mathcal{O}(s\Sigma(\log\max V-\log\epsilon))\):

#include <cstdio>
#include <cmath> typedef double f64;
const int MN = 1505, Sig = 10;
const f64 eps = 1e-6, inf = 1e99; int N, M;
char T[MN]; char str[MN];
int ch[MN][Sig], fail[MN], sum[MN], cnt;
f64 val[MN]; inline void Insert(char *s, f64 v) {
int now = 0;
for (; *s; ++s) {
if (!ch[now][*s & 15]) ch[now][*s & 15] = ++cnt;
now = ch[now][*s & 15];
} ++sum[now], val[now] += v;
} int que[MN], l, r;
void BuildAC() {
fail[0] = -1;
que[l = r = 1] = 0;
while (l <= r) {
int u = que[l++];
for (int i = 0; i < Sig; ++i) {
if (ch[u][i]) {
int x = fail[u];
while (~x && !ch[x][i]) x = fail[x];
if (~x) fail[ch[u][i]] = ch[x][i];
que[++r] = ch[u][i];
}
else if (~fail[u]) ch[u][i] = ch[fail[u]][i];
}
}
for (int i = 2; i <= r; ++i)
sum[que[i]] += sum[fail[que[i]]],
val[que[i]] += val[fail[que[i]]];
} f64 f[MN][MN];
int g[MN][MN][2];
char AT[MN];
inline f64 DP(f64 V) {
for (int j = 0; j <= cnt; ++j) val[j] -= sum[j] * V;
for (int i = 0; i <= N; ++i)
for (int j = 0; j <= cnt; ++j)
f[i][j] = -inf;
f[0][0] = 0;
for (int i = 0; i < N; ++i) {
for (int j = 0; j <= cnt; ++j) {
if (f[i][j] == -inf) continue;
if (T[i] == '.') {
for (int k = 0; k < Sig; ++k) {
int _j = ch[j][k];
if (f[i + 1][_j] < f[i][j] + val[_j])
f[i + 1][_j] = f[i][j] + val[_j],
g[i + 1][_j][0] = j,
g[i + 1][_j][1] = k;
}
}
else {
int _j = ch[j][T[i] & 15];
if (f[i + 1][_j] < f[i][j] + val[_j])
f[i + 1][_j] = f[i][j] + val[_j],
g[i + 1][_j][0] = j,
g[i + 1][_j][1] = T[i] & 15;
}
}
}
for (int j = 0; j <= cnt; ++j) val[j] += sum[j] * V;
int ans = 0;
for (int j = 1; j <= cnt; ++j)
if (f[N][j] > f[N][ans]) ans = j;
for (int i = N, j = ans; i >= 1; --i)
AT[i - 1] = g[i][j][1] | 48,
j = g[i][j][0];
return f[N][ans];
} int main() {
scanf("%d%d", &N, &M);
scanf("%s", T);
for (int i = 1; i <= M; ++i) {
f64 v;
scanf("%s%lf", str, &v);
Insert(str, log(v));
}
BuildAC();
f64 l = 0, r = log(1e9 + 5), mid, ans = 0;
while (r - l > eps) {
mid = (l + r) / 2;
if (DP(mid) > 0) ans = mid, l = mid;
else r = mid;
}
DP(ans);
printf("%s\n", AT);
return 0;
}

LOJ 3089: 洛谷 P5319: 「BJOI2019」奥术神杖的更多相关文章

  1. LOJ 3093: 洛谷 P5323: 「BJOI2019」光线

    题目传送门:LOJ #3093. 题意简述: 有 \(n\) 面玻璃,第 \(i\) 面的透光率为 \(a\),反射率为 \(b\). 问把这 \(n\) 面玻璃按顺序叠在一起后,\(n\) 层玻璃的 ...

  2. Loj #3089. 「BJOI2019」奥术神杖

    Loj #3089. 「BJOI2019」奥术神杖 题目描述 Bezorath 大陆抵抗地灾军团入侵的战争进入了僵持的阶段,世世代代生活在 Bezorath 这片大陆的精灵们开始寻找远古时代诸神遗留的 ...

  3. 【LOJ】#3089. 「BJOI2019」奥术神杖

    LOJ#3089. 「BJOI2019」奥术神杖 看见乘积就取log,开根号就是除法,很容易发现这就是一道01分数规划.. 然后建出AC自动机直接dp就行,判断条件要设成>0,因为起点的值是1, ...

  4. LOJ 3089 「BJOI2019」奥术神杖——AC自动机DP+0/1分数规划

    题目:https://loj.ac/problem/3089 没想到把根号之类的求对数变成算数平均值.写了个只能得15分的暴力. #include<cstdio> #include< ...

  5. LOJ 3045: 洛谷 P5326: 「ZJOI2019」开关

    题目传送门:LOJ #3045. 题意简述 略. 题解 从高斯消元出发好像需要一些集合幂级数的知识,就不从这个角度思考了. 令 \(\displaystyle \dot p = \sum_{i = 1 ...

  6. LOJ 3043: 洛谷 P5280: 「ZJOI2019」线段树

    题目传送门:LOJ #3043. 题意简述: 你需要模拟线段树的懒标记过程. 初始时有一棵什么标记都没有的 \(n\) 阶线段树. 每次修改会把当前所有的线段树复制一份,然后对于这些线段树实行一次区间 ...

  7. LOJ 2483: 洛谷 P4655: 「CEOI2017」Building Bridges

    题目传送门:LOJ #2483. 题意简述: 有 \(n\) 个数,每个数有高度 \(h_i\) 和价格 \(w_i\) 两个属性. 你可以花费 \(w_i\) 的代价移除第 \(i\) 个数(不能移 ...

  8. LOJ 2312(洛谷 3733) 「HAOI2017」八纵八横——线段树分治+线性基+bitset

    题目:https://loj.ac/problem/2312 https://www.luogu.org/problemnew/show/P3733 原本以为要线段树分治+LCT,查了查发现环上的值直 ...

  9. LOJ 2249: 洛谷 P2305: 「NOI2014」购票

    题目传送门:LOJ #2249. 题意简述: 有一棵以 \(1\) 号节点为根节点的带边权的树. 除了 \(1\) 号节点的所有节点上都有人需要坐车到达 \(1\) 号节点. 除了 \(1\) 号节点 ...

随机推荐

  1. BZOJ 4009: [HNOI2015]接水果

    4009: [HNOI2015]接水果 Time Limit: 60 Sec  Memory Limit: 512 MBSubmit: 636  Solved: 300[Submit][Status] ...

  2. FTP文件乱码和传输模式解释

    转: FTP文件乱码和传输模式解释 2017年02月18日 10:50:03 -Hermes- 阅读数:12112更多 所属专栏: 异常解决方案急诊室   版权声明:大侠,在转载时请注明出处,小弟不胜 ...

  3. 项目管理工具Maven的安装

    首先下载maven http://maven.apache.org/download.cgi 然后解压到不含中文和空格的目录,我直接解压到了D盘 然后添加环境变量: MAVEN_HOME:D:\apa ...

  4. NOIP 普及组 2016 回文日期

    传送门 https://www.cnblogs.com/violet-acmer/p/9859003.html 题解: 思路1: 相关变量解释: year1,month1,day1 : date1对应 ...

  5. Linux系统下yum镜像源环境部署记录

    之前介绍了Linux环境下本地yum源配置方法,不过这个是最简单最基础的配置,在yum安装的时候可能有些软件包不够齐全,下面说下完整yun镜像源系统环境部署记录(yum源更新脚本下载地址:https: ...

  6. GUI程序开发的流程(随时删除的源码)

    1.继承JFrame 2.定义需要的组件 3.创建组件 4.设置布局管理器 5.添加组件 6.显示窗体 --------------------------------------------- 小代 ...

  7. Scala进阶之路-并发编程模型Akka入门篇

    Scala进阶之路-并发编程模型Akka入门篇 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Akka Actor介绍 1>.Akka介绍 写并发程序很难.程序员不得不处 ...

  8. 学习windows编程 day3 之 设置当前的背景颜色

    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRU ...

  9. 学习windows编程 day3 之窗口绘画一:点线绘制

    #include <windows.h> #include <math.h> LRESULT CALLBACK WndProc(HWND hwnd, UINT message, ...

  10. Windows 上安装 Redis 及可能出现的错误和解决方法!

    前言 Redis(REmote Dictionary Server) 是一种以key-value写得存储系统.他是开源的ANSI语言编写的.遵守BSD协议.被称作“数据结构服务器”,因为它的值(val ...