题目传送门

题目大意

给出一个残缺的字符串,每个位置都 \(\in[0,9]\)。有 \(m\) 中贡献,即 \(s,k\),表示该字符串中没出现一次 \(s\),贡献便乘上 \(k\)。最后对贡献求 \(c\) 次根,其中 \(c\) 是总出现次数。求贡献的最大值。

字符串长度以及贡献字符串长度之和 \(\le 1500\)

思路

首先你需要想到我们可以全部取 \(\ln\),然后每次贡献就是 \(+k\),求根就是 \(/c\),于是问题就是最大化:

\[\frac{\sum k}{c}
\]

然后你对这个二分,判断条件就是:

\[\sum_{k-mid}>0
\]

于是我们可以在 AC 自动机上进行dp,即设 \(f_{i,j}\) 表示到第 \(i\) 个字符串对应自动机上状态j时的最大贡献,转移显然。

于是,我们就可以在 \(nl\log w\) 的时间复杂度内解决这个问题。

\(\texttt{Code}\)

#include <bits/stdc++.h>
using namespace std; #define Int register int
#define MAXN 2005 template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');} int n,m;
int g[MAXN][MAXN][2];
double dp[MAXN][MAXN];
char s1[MAXN],s2[MAXN],ans[MAXN]; struct Auto{
double val[MAXN];
int cnt,ch[MAXN][10],fail[MAXN],sum[MAXN];
void Insert (char *s,double v){
int now = 0;
for (Int i = 1;s[i];++ i){
if (!ch[now][s[i] - '0']) ch[now][s[i] - '0'] = ++ cnt;
now = ch[now][s[i] - '0'];
}
sum[now] ++,val[now] += v;
}
void Build (){
queue <int> q;
while (!q.empty()) q.pop ();
for (Int i = 0;i < 10;++ i) if (ch[0][i]) q.push (ch[0][i]);
while (!q.empty()){
int u = q.front();q.pop ();
sum[u] += sum[fail[u]],val[u] += val[fail[u]];
for (Int i = 0;i < 10;++ i){
if (ch[u][i]) fail[ch[u][i]] = ch[fail[u]][i],q.push (ch[u][i]);
else ch[u][i] = ch[fail[u]][i];
}
}
}
double Work (double v){
for (Int i = 0;i <= cnt;++ i) val[i] -= sum[i] * v;
for (Int i = 0;i <= n;++ i) for (Int j = 0;j <= cnt;++ j) dp[i][j] = -1e6;
dp[0][0] = 0;
for (Int i = 0;i < n;++ i)
for (Int j = 0;j <= cnt;++ j)
if (dp[i][j] > -1e5)
for (Int k = 0;k < 10;++ k)
if (s1[i] == '.' || s1[i] == k + '0'){
int t = ch[j][k];
if (dp[i + 1][t] < dp[i][j] + val[t]){
dp[i + 1][t] = dp[i][j] + val[t];
g[i + 1][t][0] = k,g[i + 1][t][1] = j;
}
}
for (Int i = 0;i <= cnt;++ i) val[i] += sum[i] * v;
int pos = 0;for (Int i = 0;i <= cnt;++ i) if (dp[n][i] > dp[n][pos]) pos = i;
for (Int i = n,now = pos;i;-- i) ans[i] = g[i][now][0] + '0',now = g[i][now][1];
return dp[n][pos];
}
}T; signed main(){
read (n,m);
scanf ("%s",s1);
for (Int i = 1,v;i <= m;++ i){
scanf ("%s",s2 + 1),read (v);
T.Insert (s2,log (v));
}
T.Build();
double l = 0,r = 1e9;
while (r - l > 1e-3){
double mid = (l + r) / 2;
if (T.Work(mid) > 0) l = mid;
else r = mid;
}
T.Work(l),printf ("%s",ans + 1);
return 0;
}

题解 [BJOI2019]奥术神杖的更多相关文章

  1. [BJOI2019]奥术神杖(分数规划,动态规划,AC自动机)

    [BJOI2019]奥术神杖(分数规划,动态规划,AC自动机) 题面 洛谷 题解 首先乘法取\(log\)变加法,开\(c\)次根变成除\(c\). 于是问题等价于最大化\(\displaystyle ...

  2. luoguP5319 [BJOI2019]奥术神杖(分数规划,AC自动机DP)

    luoguP5319 [BJOI2019]奥术神杖(分数规划,AC自动机DP) Luogu 题解时间 难点在于式子转化,设有c个满足的子串,即求最大的 $ ans = \sqrt[c]{\prod_{ ...

  3. [BJOI2019]奥术神杖——AC自动机+DP+分数规划+二分答案

    题目链接: [BJOI2019]奥术神杖 答案是$ans=\sqrt[c]{\prod_{i=1}^{c}v_{i}}=(\prod_{i=1}^{c}v_{i})^{\frac{1}{c}}$. 这 ...

  4. 【题解】Luogu P5319 [BJOI2019]奥术神杖

    原题传送门 题目让我们最大化\(val=\sqrt[k]{\prod_{i=1}^k w_i}\),其中\(k\)是咒语的个数,\(w_i\)是第\(i\)个咒语的神力 看着根号和累乘不爽,我们两边同 ...

  5. [BJOI2019]奥术神杖

    https://www.luogu.org/problemnew/show/P5319 题解 首先观察我们要求的答案的形式: \[ \biggl(\prod V_i \biggr)^x\ \ \ x= ...

  6. [BJOI2019]奥术神杖(分数规划+AC自动机+DP)

    题解:很显然可以对权值取对数,然后把几何平均值转为算术平均值,然后很显然是分数规划.先对每个模式串建立AC自动机,每个节点w[i],sz[i]分别表示以其为前缀的字符串,然后再二分最优解k,然后w[i ...

  7. luogu P5319 [BJOI2019]奥术神杖

    传送门 要求的东西带个根号,这玩意叫几何平均数,说到平均数,我们就能想到算术平均数(就是一般意义下的平均数),而这个东西是一堆数之积开根号,所以如果每个数取对数,那么乘法会变成加法,开根号变成除法,所 ...

  8. #loj3089 [BJOI2019]奥术神杖

    卡精度好题 最关键的一步是几何平均数的\(ln\)等于所有数字取\(ln\)后的算术平均值 那么现在就变成了一个很裸的01分数规划问题,一个通用的思路就是二分答案 现在来考虑二分答案的底层怎么写 把所 ...

  9. [BJOI2019]奥术神杖(AC自动机,DP,分数规划)

    题目大意: 给出一个长度 $n$ 的字符串 $T$,只由数字和点组成.你可以把每个点替换成一个任意的数字.再给出 $m$ 个数字串 $S_i$,第 $i$ 个权值为 $t_i$. 对于一个替换方案,这 ...

随机推荐

  1. Go版本依赖--版本选择机制

    目录 1. 版本选择机制 2.依赖包版本约定 2.1 Go module 之前版本兼容性 2.2 Go module 之后版本兼容性 3. 版本选择机制 3.1 最新版本选择 3.2 最小版本选择 1 ...

  2. MyBatis学习总结(一)——MyBatis入门学习

    一.MyBatis 简介 MyBatis是一个支持普通SQL查询,存储过程和高级映射的优秀持久层框架.MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装.MyBatis可 ...

  3. Spring AOP Aspect的简单实现(基于XML)

    第一步:导包 第二步:实现类和切面类 Service("userService")public class IUserviceImpl implements IUserServic ...

  4. struts2执行流程和架构图

    一.struts2执行流程 二.架构图 只需要编写黄色部分的代码:

  5. 自定义组件 v-model 的使用

    关于自定义组件如何使用 v-model,本章直讲如何使用: 一. $emit('input', params) // 父组件中 <template> <article> {{f ...

  6. 离散化模板题 II ——重复元素离散化后的数字不相同

    离散化模板题 II --重复元素离散化后的数字不相同 题目描述 现有数列A1, A2, ⋯, An,数列中可能有重复元素. 现在要求输出该数列的离散化数列,重复元素离散化后的数字不相同. 输入 第一行 ...

  7. 洛谷P1781——宇宙总统(高精度排序)

    题目描述 地球历公元6036年,全宇宙准备竞选一个最贤能的人当总统,共有n个非凡拔尖的人竟选总统,现在票数已经统计完毕,请你算出谁能够当上总统. 输入输出格式 输入格式: 第一行为一个整数n,代表竞选 ...

  8. Docker安装flink及避坑指南

    Docker安装flink 导航 无处不在的大数据 安装flink 拉取flink镜像 编写docker-compose.yml 生成启动 查看安装效果 常见坑及解决方案 问题1 问题2 参考   本 ...

  9. prometheus、node_exporter设置开机自启动

    方法一.写入rc.local 在/etc/rc.local文件中编辑需要执行的脚本或者命令,我个人习惯用这个,因人而异,有的项目可能需要热加载配置文件,用服务会更好 #普罗米修斯启动,需要后面接con ...

  10. Jmeter系列(13)- 数据库操作之JDBC Connection Configuration配置元件、JDBC Request取样器

    Jmeter常见操作数据库场景 准备.制造测试数据 获取.查询测试数据 数据库数据作为参数引用 清理测试环境.删除过程数据 数据库压测 Jmeter操作数据库环境准备 已经安装好的数据库,比如MySq ...