【题解】Luogu P5319 [BJOI2019]奥术神杖
原题传送门
题目让我们最大化\(val=\sqrt[k]{\prod_{i=1}^k w_i}\),其中\(k\)是咒语的个数,\(w_i\)是第\(i\)个咒语的神力
看着根号和累乘不爽,我们两边同取\(\ln\)
$$\ln val=\frac{1}{k}\sum_{i=1}^k \ln w_i$$
易知当\(\ln val\)最大化时,\(val\)也最大化。所以我们将问题转化成了最大化\(\frac{1}{k}\sum_{i=1}^k \ln w_i\),我们发现这是算数平均数。我们珂以通过二分答案找到它的最大值,问题就是二分答案如何check是否合法:
当\(\frac{1}{k}\sum_{i=1}^k \ln w_i>mid\)时才合法
即当\(\sum_{i=1}^k(w_i-mid)>0\)时才合法
我们先对所有咒语建AC自动机,在上面跑dp求出\(\sum_{i=1}^k(w_i-mid)\)的最大值,判断是否可行
具体dp:就像其他很多AC自动机上的dp一样,设\(f[i][j]\)表示神杖前\(i\)个字符,匹配到了AC自动机上\(j\)号节点,依照套路转移,就是不要忘了题目原有的限制
此算法精度误差较大,但本题还是珂以通过
#include <bits/stdc++.h>
#define db double
#define N 1505
#define eps 1e-6
using namespace std;
inline int read()
{
register int x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
int n,m;
char T[N],s[N],ans[N];
db V[N],val[N],f[N][N];
pair<int,int> pre[N][N];
struct node{
int son[10],fail,cnt;
db val;
}tr[N];
int tot=0;
inline void Insert(register char *s,register db v)
{
int len=strlen(s+1),now=0;
for(register int i=1;i<=len;++i)
{
if(!tr[now].son[s[i]-'0'])
tr[now].son[s[i]-'0']=++tot;
now=tr[now].son[s[i]-'0'];
}
++tr[now].cnt,tr[now].val+=v;
}
inline void getfail()
{
queue<int> q;
for(register int i=0;i<10;++i)
if(tr[0].son[i])
q.push(tr[0].son[i]);
while(!q.empty())
{
int u=q.front();
q.pop();
tr[u].cnt+=tr[tr[u].fail].cnt;
tr[u].val+=tr[tr[u].fail].val;
for(register int i=0;i<10;++i)
{
if(tr[u].son[i])
{
tr[tr[u].son[i]].fail=tr[tr[u].fail].son[i];
q.push(tr[u].son[i]);
}
else
tr[u].son[i]=tr[tr[u].fail].son[i];
}
}
}
inline void updateans(register int i,register int j)
{
if(!i)
return;
updateans(i-1,pre[i][j].first);
ans[i]=pre[i][j].second+'0';
}
inline bool check(register db mid)
{
memset(f,-0x3f,sizeof(f));
db inf=-f[0][0];
f[0][0]=0;
for(register int i=1;i<=n;++i)
for(register int j=0;j<=tot;++j)
{
if(fabs(f[i-1][j]+inf)<1)
continue;
if(T[i]=='.')
{
for(register int k=0;k<10;++k)
{
int v=tr[j].son[k];
if(f[i-1][j]+tr[v].val-tr[v].cnt*mid>f[i][v])
{
f[i][v]=f[i-1][j]+tr[v].val-tr[v].cnt*mid;
pre[i][v]=make_pair(j,k);
}
}
}
else
{
int k=T[i]-'0',v=tr[j].son[k];
if(f[i-1][j]+tr[v].val-tr[v].cnt*mid>f[i][v])
{
f[i][v]=f[i-1][j]+tr[v].val-tr[v].cnt*mid;
pre[i][v]=make_pair(j,k);
}
}
}
int pos=0;
for(register int i=1;i<=tot;++i)
if(f[n][i]>f[n][pos])
pos=i;
if(f[n][pos]>eps)
{
updateans(n,pos);
return 1;
}
else
return 0;
}
int main()
{
n=read(),m=read();
scanf("%s",T+1);
db L=0,R=0;
for(register int i=1;i<=m;++i)
{
scanf("%s",s+1);
V[i]=log(read());
R=max(R,V[i]);
Insert(s,V[i]);
}
getfail();
while(R-L>eps)
{
db mid=(L+R)/2.0;
if(check(mid))
L=mid;
else
R=mid;
}
for(register int i=1;i<=n;++i)
putchar(ans[i]);
return 0;
}
【题解】Luogu P5319 [BJOI2019]奥术神杖的更多相关文章
- luogu P5319 [BJOI2019]奥术神杖
传送门 要求的东西带个根号,这玩意叫几何平均数,说到平均数,我们就能想到算术平均数(就是一般意义下的平均数),而这个东西是一堆数之积开根号,所以如果每个数取对数,那么乘法会变成加法,开根号变成除法,所 ...
- luoguP5319 [BJOI2019]奥术神杖(分数规划,AC自动机DP)
luoguP5319 [BJOI2019]奥术神杖(分数规划,AC自动机DP) Luogu 题解时间 难点在于式子转化,设有c个满足的子串,即求最大的 $ ans = \sqrt[c]{\prod_{ ...
- [BJOI2019]奥术神杖(分数规划,动态规划,AC自动机)
[BJOI2019]奥术神杖(分数规划,动态规划,AC自动机) 题面 洛谷 题解 首先乘法取\(log\)变加法,开\(c\)次根变成除\(c\). 于是问题等价于最大化\(\displaystyle ...
- [BJOI2019]奥术神杖——AC自动机+DP+分数规划+二分答案
题目链接: [BJOI2019]奥术神杖 答案是$ans=\sqrt[c]{\prod_{i=1}^{c}v_{i}}=(\prod_{i=1}^{c}v_{i})^{\frac{1}{c}}$. 这 ...
- 题解 [BJOI2019]奥术神杖
题目传送门 题目大意 给出一个残缺的字符串,每个位置都 \(\in[0,9]\).有 \(m\) 中贡献,即 \(s,k\),表示该字符串中没出现一次 \(s\),贡献便乘上 \(k\).最后对贡献求 ...
- [BJOI2019]奥术神杖
https://www.luogu.org/problemnew/show/P5319 题解 首先观察我们要求的答案的形式: \[ \biggl(\prod V_i \biggr)^x\ \ \ x= ...
- [BJOI2019]奥术神杖(分数规划+AC自动机+DP)
题解:很显然可以对权值取对数,然后把几何平均值转为算术平均值,然后很显然是分数规划.先对每个模式串建立AC自动机,每个节点w[i],sz[i]分别表示以其为前缀的字符串,然后再二分最优解k,然后w[i ...
- #loj3089 [BJOI2019]奥术神杖
卡精度好题 最关键的一步是几何平均数的\(ln\)等于所有数字取\(ln\)后的算术平均值 那么现在就变成了一个很裸的01分数规划问题,一个通用的思路就是二分答案 现在来考虑二分答案的底层怎么写 把所 ...
- [BJOI2019]奥术神杖(AC自动机,DP,分数规划)
题目大意: 给出一个长度 $n$ 的字符串 $T$,只由数字和点组成.你可以把每个点替换成一个任意的数字.再给出 $m$ 个数字串 $S_i$,第 $i$ 个权值为 $t_i$. 对于一个替换方案,这 ...
随机推荐
- 周黑鸭借力MES,推进智能生产
1.项目背景介绍 中国食品企业在经过了一些年的行业整体快速增长后,国家对食品行业的管理提出了更加严格的要求,控制更严,准入门槛提高,企业数量成下降趋势. 大中型食品企业已经需要走出国门,走向国际市场, ...
- cpio建立、还原备份档
1. 简介 加入.解开cpio或tar备份档内的文件 与tar相似,将文件归档到硬盘或磁带等存储设备中 2. tar比较 在所处理的文件类型方面,它比tar更全面,但也更复杂 cpio比tar更为可靠 ...
- js,获取字符串中存在中文的个数
var RespMemo='1231231617440C01 心存正义 10'; //定义字符串 re = /[\u4E00-\u9FA5]/g; //测试中文字符的正则 var ...
- Redis_数据类型
Redis支持的键值数据类型如下: 字符串类型 散列类型 列表类型 集合类型 有序集合类型 一.字符串类型 字符串类型是Redis中最基本的数据类型,它能存储任何形式的字符串,包括二进制数据.一个字 ...
- h5表单亲测
Document 下载进度: 标签. 牛奶 面包 男 女 one two three 按钮 搜索 请输入搜索内容 加密强度 用户名 Email 密码 年龄 身高 生日 这一系列是很酷的一个类型,完全解 ...
- Leetcode周赛164
目录 访问所有点的最小时间 思路 代码 统计参与通信的服务器 思路 代码 搜索推荐系统 思路 代码 停在原地的方案数 思路 代码 访问所有点的最小时间 思路 由于每次移动有水平方向移动一格.竖直方向移 ...
- js 驼峰命名和下划线互换
代码走你 // 下划线转换驼峰 function toHump(name) { return name.replace(/\_(\w)/g, function(all, letter){ return ...
- 201671030129 周婷 实验十四 团队项目评审&课程学习总结
项目 内容 这个作业属于哪个课程 软件工程 这个作业的要求在哪里 团队项目评审&课程学习总结 课程学习目标 (1)完成项目验收(2)反思总结课程学习内容 1.对<实验一 软件工程准备&g ...
- Memcache未授权访问漏洞简单修复方法
漏洞描述: memcache是一套常用的key-value缓存系统,由于它本身没有权限控制模块,所以开放在外网的memcache服务很容易被攻击者扫描发现,通过命令交互可直接读取memcache中的敏 ...
- 2017-2018 ACM-ICPC Southeastern European Regional Programming Contest (SEERC 2017)
2017-2018 ACM-ICPC Southeastern European Regional Programming Contest (SEERC 2017) 全靠 wxh的博客 补完这套.wx ...