[BJOI2019]奥术神杖(AC自动机,DP,分数规划)
题目大意:
给出一个长度 $n$ 的字符串 $T$,只由数字和点组成。你可以把每个点替换成一个任意的数字。再给出 $m$ 个数字串 $S_i$,第 $i$ 个权值为 $t_i$。
对于一个替换方案,这样定义它的价值:
如果数字串 $S_i$ 在 $T$ 中出现了,那么将 $t_i$ 加入多重集。如果出现多次也要加多次。
它的价值就是这个多重集元素的几何平均数(所有 $c$ 个数的乘积开 $c$ 次方根)。
请构造出一个替换方案,使得这个值最大。不用输出这个价值。
$1\le n\le 1500,1\le \sum|S_i|\le 1500,1\le t_i\le 10^9$。
首先这个奇怪的式子是乘积的形式。如果将它取对数:(其实不一定要用 $\ln$,任意底数都可以)
$$\dfrac{1}{c}\sum\limits_{i=1}^c\ln x_i$$
$$\dfrac{\sum\limits_{i=1}^c\ln x_i}{\sum\limits_{i=1}^c 1}$$
这就是分数规划经典模式了。
二分 $x$,看看这个式子的值能不能 $>v$。可以就缩小左边界,否则缩小右边界。
$$\dfrac{1}{c}\sum\limits_{i=1}^c\ln x_i>v$$
$$\sum\limits_{i=1}^c\ln x_i>vc$$
$$\sum\limits_{i=1}^c(\ln x_i-v)>0$$
设第 $i$ 个串的新权值 $w_i=\ln x_i-v$,那么就是要找出一个方案使得 $w_i$ 之和最大,看看是否 $>0$ 即可。
如何求最大值?实际上是个套路 DP 了。
先建出所有 $S_i$ 串的 AC 自动机。然后设 $wsum_u$ 为从 $u$ 开始跳 fail 指针,跳过的所有点的 $w_i$ 之和。要记录这个是因为在 AC 自动机上走到点 $u$ 时,沿着 $u$ 跳 fail 能跳到的所有点都是可以匹配的。
令 $f[i][j]$ 表示按照 $T$ 串走了 $i$ 步,走到点 $j$ 的最大值。
可以从 $f[i][j]+wsum_c$ 转移到 $f[i+1][c]$。其中 $T_{i+1}$ 已经确定时 $c$ 就是对应的儿子,否则就要枚举替换成什么字符,再转移到相应的儿子。
由于要输出方案,要记录从哪个状态转移过来。
时间复杂度 $O(n\sum|S_i|\log)$。
#include<bits/stdc++.h>
using namespace std;
const int maxn=;
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define ROF(i,a,b) for(int i=(a);i>=(b);i--)
#define MEM(x,v) memset(x,v,sizeof(x))
inline int read(){
char ch=getchar();int x=,f=;
while(ch<'' || ch>'') f|=ch=='-',ch=getchar();
while(ch>='' && ch<='') x=x*+ch-'',ch=getchar();
return f?-x:x;
}
int n,m,nd,ch[maxn][],fail[maxn],cnt[maxn],q[maxn],h,r,fr[maxn][maxn],id[maxn][maxn];
double val[maxn],hhh[maxn],dp[maxn][maxn];
char s[maxn],t[maxn],tmp[maxn];
void insert(const char *s,int x){
int now=,l=strlen(s+);
FOR(i,,l){
int p=s[i]-'';
if(!ch[now][p]) ch[now][p]=++nd;
now=ch[now][p];
}
val[now]+=log(x);
cnt[now]++;
}
void build(){
h=;r=;
FOR(i,,) if(ch[][i]) q[++r]=ch[][i];
while(h<=r){
int u=q[h++];
val[u]+=val[fail[u]];
cnt[u]+=cnt[fail[u]];
FOR(i,,) if(ch[u][i]) fail[q[++r]=ch[u][i]]=ch[fail[u]][i];
else ch[u][i]=ch[fail[u]][i];
}
}
void trans(int i,int j,int k){
int c=ch[j][k];
if(dp[i][j]+hhh[c]>dp[i+][c]){
dp[i+][c]=dp[i][j]+hhh[c];
fr[i+][c]=j;
id[i+][c]=k;
}
}
bool check(double x){
FOR(i,,nd) hhh[i]=val[i]-cnt[i]*x;
FOR(i,,n) FOR(j,,nd) dp[i][j]=-1e9;
dp[][]=;
FOR(i,,n-) FOR(j,,nd){
if(s[i+]=='.') FOR(k,,) trans(i,j,k);
else trans(i,j,s[i+]-'');
}
int mxid=;
FOR(i,,nd) if(dp[n][i]>dp[n][mxid]) mxid=i;
if(dp[n][mxid]<=) return false;
int at=mxid;
ROF(i,n,){
t[i]=id[i][at]+'';
at=fr[i][at];
}
return true;
}
int main(){
n=read();m=read();
scanf("%s",s+);
FOR(i,,m){
scanf("%s",tmp+);
insert(tmp,read());
}
build();
double l=,r=log(1e9);
while(r-l>1e-){
double mid=(l+r)/;
if(check(mid)) l=mid;
else r=mid;
}
check(l);
printf("%s\n",t+);
}
[BJOI2019]奥术神杖(AC自动机,DP,分数规划)的更多相关文章
- [BJOI2019]奥术神杖——AC自动机+DP+分数规划+二分答案
题目链接: [BJOI2019]奥术神杖 答案是$ans=\sqrt[c]{\prod_{i=1}^{c}v_{i}}=(\prod_{i=1}^{c}v_{i})^{\frac{1}{c}}$. 这 ...
- LOJ 3089 「BJOI2019」奥术神杖——AC自动机DP+0/1分数规划
题目:https://loj.ac/problem/3089 没想到把根号之类的求对数变成算数平均值.写了个只能得15分的暴力. #include<cstdio> #include< ...
- P5319-[BJOI2019]奥术神杖【0/1分数规划,AC自动机,dp】
正题 题目链接:https://www.luogu.com.cn/problem/P5319 题目大意 一个长度为\(n\)的串\(T\),用\(0\sim 9\)填充所有的\(.\). 然后给出\( ...
- luoguP5319 [BJOI2019]奥术神杖(分数规划,AC自动机DP)
luoguP5319 [BJOI2019]奥术神杖(分数规划,AC自动机DP) Luogu 题解时间 难点在于式子转化,设有c个满足的子串,即求最大的 $ ans = \sqrt[c]{\prod_{ ...
- [BJOI2019]奥术神杖(分数规划,动态规划,AC自动机)
[BJOI2019]奥术神杖(分数规划,动态规划,AC自动机) 题面 洛谷 题解 首先乘法取\(log\)变加法,开\(c\)次根变成除\(c\). 于是问题等价于最大化\(\displaystyle ...
- POJ1625 Censored!(AC自动机+DP)
题目问长度m不包含一些不文明单词的字符串有多少个. 依然是水水的AC自动机+DP..做完后发现居然和POJ2778是一道题,回过头来看都水水的... dp[i][j]表示长度i(在自动机转移i步)且后 ...
- HDU2296 Ring(AC自动机+DP)
题目是给几个带有价值的单词.而一个字符串的价值是 各单词在它里面出现次数*单词价值 的和,问长度不超过n的最大价值的字符串是什么? 依然是入门的AC自动机+DP题..不一样的是这题要输出具体方案,加个 ...
- HDU2457 DNA repair(AC自动机+DP)
题目一串DNA最少需要修改几个基因使其不包含一些致病DNA片段. 这道题应该是AC自动机+DP的入门题了,有POJ2778基础不难写出来. dp[i][j]表示原DNA前i位(在AC自动机上转移i步) ...
- hdu 4117 GRE Words AC自动机DP
题目:给出n个串,问最多能够选出多少个串,使得前面串是后面串的子串(按照输入顺序) 分析: 其实这题是这题SPOJ 7758. Growing Strings AC自动机DP的进阶版本,主题思想差不多 ...
- hdu 2457(ac自动机+dp)
题意:容易理解... 分析:这是一道比较简单的ac自动机+dp的题了,直接上代码. 代码实现: #include<stdio.h> #include<string.h> #in ...
随机推荐
- JAVA 运行springboot jar包设置classpath
Java 命令行提供了如何扩展bootStrap 级别class的简单方法. -Xbootclasspath: 完全取代基本核心的Java class 搜索路径.不常用,否则要重新写所有Java 核心 ...
- DFS(三):八皇后问题
[例1]八皇后问题. 在一个8×8国际象棋盘上,放置8个皇后,每个皇后占一格,要求皇后间不会出现相互“攻击”的现象,即不能有两个皇后处在同一行.同一列或同一对角线上.问共有多少种不同的放置方法? (1 ...
- jpa复杂查询groupby失败的原因以及替代方法-20190824
问题 1 jpa specification 复杂查询,拼接group by 时,分页会触发select count (*),导致指定select * from table group by 字段 ...
- iview 组件的额外传参问题记录
在使用iview组件的时候,经常遇到额外传参的问题,一般情况下可以使用以下2种方法都可以解决: 1.直接在方法后面输入参数,有的时候借用$event获取当前dom信息,在某些特定情况下可以将参数绑定在 ...
- flask 第一章
1.安装flask 首先安装python的虚拟环境,每个环境之间的包并不会产生冲突 ,相当于一个单独的 小空间. 由于自己使用的是windows开发环境 所以安装虚拟包的命令如下 pip inst ...
- HTML+css基础 css的几种形式
1.行间样式:将style写在标签内的充当标签标签属性 2.行内样式
- 用Maven整合SSM框架
前述 Maven 是专门用于构建和管理Java相关项目的工具,利用 Maven 的主要目的是统一维护 jar 包.关于 Maven 的安装在这篇里面就不说了. SSM(Spring+SpringMVC ...
- Django学习笔记(16)——扩展Django自带User模型,实现用户注册与登录
一,项目题目:扩展Django自带User模型,实现用户注册与登录 我们在开发一个网站的时候,无可避免的需要设计实现网站的用户系统.此时我们需要实现包括用户注册,登录,用户认证,注销,修改密码等功能. ...
- matplotlib基础
Matplotlib 基础 注:本文中的程序都默认引入了numpy库和matplotlib库,并且分别简写为np与plt:如果读者不知道怎么使用numpy库,可以移步到这一博客上进行简单的学习 一.简 ...
- ArcGIS Server 地图发布请求分析
1.1. 数据上传 请求 URL: https://172.16.2.17:6443/arcgis/admin/uploads/upload POST Location: ...