[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 ...
随机推荐
- linux系统中启动daytime服务
环境:vmware下面的cetos6 1. 进入/etc/xinetd.d/目录下,查看是否存在daytime服务,若不存在,则须安装: 执行命令:yum install xinetd 该命令执行后会 ...
- cap理论与分布式事务的解决方案
现在很火的微服务架构所设计的系统是分布式系统.分布式系统有一个著名的CAP理论,即一个分布式系统要同时满足一致性(Consistency).可用性(Availablility)和分区容错(Partit ...
- WPF ItemsSource Order by Getter
public ObservableCollection<CustomerModel> CustomerCollection { get { if(customerCollection!=n ...
- vue笔记(一)
Vue的开发 一丶下载 # 中文下载地址: https://cn.vuejs.org/ # 使用方式: # 1. 单独使用 vue.min.js.文件 # 2. 结合node.js使用集成工具 二丶v ...
- WebService 创建、发布、调用
环境Win7+VS2017 启用IIS 查看iis是否启用 新建 ASP.NET Web 应用程序 项目,项目中添加Web 服务 在 asmx 文件中添加需要的方法 运行结果 发布 创建新的文件夹, ...
- Java基础之 集合体系结构(Collection、List、ArrayList、LinkedList、Vector)
Java基础之 集合体系结构详细笔记(Collection.List.ArrayList.LinkedList.Vector) 集合是JavaSE的重要组成部分,其与数据结构的知识密切相联,集合体系就 ...
- Scrum冲刺第三篇
一.每日例会 会议照片 成员 昨日已完成的工作 今日计划完成的工作 工作中遇到的困难 陈嘉欣 撰写博客,管理成员提交代码 每日博客,根据队员代码问题更改规范文档安排后续工作 队员提交的代码管理困难 邓 ...
- 【web后端开发】笔试题收集
4399Web后端开发笔试题 题目来源:牛客网 1.linux中,用mkdir命令创建新的目录时,如果需要在其父目录不存在时先创建父目录的选项是 D A -h B -d C -f D -p [ ...
- Mysql时区无法识别
Unable to connect to database. Tried 1 times {:error_message=>“Java::JavaSql::SQLException: The s ...
- Django框架(二十一)--Django rest_framework-频率组件
一.作用 为了控制用户对某个url请求的频率,比如,一分钟以内,只能访问三次 二.自定义频率类 # 写一个频率认证类 class MyThrottle: visit_dic = {} visit_ti ...