题目传送门: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. codeforces 777C

    C.Alyona and Spreadsheet During the lesson small girl Alyona works with one famous spreadsheet compu ...

  2. 自学Zabbix9.2 zabbix网络发现规则配置详解+实战

    点击返回:自学Zabbix之路 点击返回:自学Zabbix4.0之路 点击返回:自学zabbix集锦 自学Zabbix9.2 zabbix网络发现规则配置详解+实战 1.  创建网络发现规则 Conf ...

  3. BZOJ 4004 [JLOI2015]装备购买 | 线性基

    题目链接 Luogu P3265 题解 非常正常的线性基! 但是我不会线性基-- (吐槽:#define double long double 才过--) #include <cstdio> ...

  4. 部署kubernetes1.8.3高可用集群

    Kubernetes作为容器应用的管理平台,通过对pod的运行状态进行监控,并且根据主机或容器失效的状态将新的pod调度到其他node上,实现了应用层的高可用. 针对kubernetes集群,高可用性 ...

  5. Spring3.x 获取properties资源文件的值

    Spring3.x 获取properties资源文件的值有两种方式:  第一种:使用<context:property-placeholder />标签  <context:prop ...

  6. 解码(ByteBuffer): CharsetDecoder.decode() 与 Charset.decode() 的不同

    今天测试的时候发现一个问题: ByteBuffer inputBuffer = ByteBuffer.allocate(1024); StringBuilder inputData = new Str ...

  7. vue2.0 keep-alive最佳实践

    1.基本用法 vue2.0提供了一个keep-alive组件用来缓存组件,避免多次加载相应的组件,减少性能消耗 <keep-alive> <component> <!-- ...

  8. 洛谷P2148 [SDOI2009]E&D(博弈论)

    洛谷题目传送门 先安利蒟蒻仍在施工的博弈论总结 首先根据题目,石子被两两分组了,于是根据SG定理,我们只要求出每一组的SG值再全部异或起来就好啦. 把每一对数看成一个ICG,首先,我们尝试构造游戏的状 ...

  9. DTLS协议中client/server的认证过程和密钥协商过程

    我的总结:DTLS的握手就是协商出一个对称加密的秘钥(每个客户端的秘钥都会不一样),之后的通信就要这个秘钥进行加密通信.协商的过程要么使用非对称加密算法进行签名校验身份,要么通过客户端和服务器各自存对 ...

  10. 弹指之间 -- Polychord

    CHAPTER 19 复合和弦 Polychord 示例歌曲:爱很简单,恰是你的温柔