题面

传送门

思路

首先,看到这个乘起来开根号的形式,应该能想到用取$\log$的方式做一个转化:

$\sqrt[n]{\prod_i a_i}=\frac{1}{n}\sum_i \log_b a_i$

这里我们把$b$取到$e$,就是$\ln a_i$了,不过实际上$b$取什么都没有问题

那么,这个问题就转化为了求所有匹配的宝石序列的最大平均值

遇到这种多模式串、单模板串的情况,应当第一时间想到AC自动机

我们建立模式串的AC自动机,并在上面跑dp即可完成题目的求解

建立AC自动机的时候,注意每个节点需要继承$fail$树上所有祖先的信息!

遇到这种有对选取的元素求平均值的最值的情况,应当第一时间想到0-1分数规划

我们二分最大平均值的答案,设当前为$C$

那么若有一组匹配方式能达到这个$C$,或以上,则有:

$\frac{1}{siz}\sum_{i=1}^{siz}w_i\geq C$

$\sum_{i=1}^{siz}w_i\geq C\ast siz$

$\sum_{i=1}^{siz}(w_i-C)\geq 0$

所以我们把每一个取过$\log$的元素减去当前二分的$C$,在AC自动机上跑dp

这样的好处是避免了需要在dp中维护已匹配元素个数的一个维度,可以优化一个$n$的时间复杂度

建立AC自动机后,设$dp[i][u]$表示当前遍历完成了模板串的前$i$个字符,匹配指针位置在AC自动机节点$u$上的情况时的最大值。

若模板串的下一个字符是确定的,就直接走到对应的儿子即可

否则需要更新每一个$dp[i+1][son_u]$的值

详细的更新方式见代码

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cassert>
#include<queue>
#include<cmath>
#define ll long long
using namespace std;
inline int read(){
int re=0,flag=1;char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') flag=-1;
ch=getchar();
}
while(isdigit(ch)) re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
return re*flag;
}
int n,m;double w[1510];
char a[1510],s[1510][1510];
int ch[1510][10],cntn=0,num[1510],fail[1510];
double sum[1510];
//AC Automaton
inline void insert(int x,int len){
int i,cur=0,tmp;
for(i=1;i<=len;i++){
tmp=s[x][i]-'0';
if(!ch[cur][tmp]) ch[cur][tmp]=++cntn;
cur=ch[cur][tmp];
}
num[cur]++;sum[cur]+=w[x];
}
queue<int>q;
inline void build(){
int i,u,v;
for(i=0;i<10;i++){
if(!ch[0][i]) continue;
q.push(ch[0][i]);fail[ch[0][i]]=0;
}
while(!q.empty()){
u=q.front();q.pop();
num[u]+=num[fail[u]];
sum[u]+=sum[fail[u]];
for(i=0;i<10;i++){
v=ch[u][i];
if(v) fail[v]=ch[fail[u]][i],q.push(v);
else ch[u][i]=ch[fail[u]][i];
}
}
}
//Dynamic Programming
double dp[1510][1510];
int from[1510][1510][2],endpos;
inline bool check(double mid){
int i,j,k,son;
for(i=0;i<=n;i++) for(j=0;j<=cntn;j++) dp[i][j]=-2e20;
for(i=0;i<=cntn;i++){
sum[i]-=mid*(double)num[i];//cut the value according to binary search process
}
dp[0][0]=0;
for(i=1;i<=n;i++){
for(j=0;j<=cntn;j++){
if(dp[i-1][j]==-2e20) continue;
if(a[i]!='.'){//character is fixed in original S
son=ch[j][a[i]-'0'];
if(dp[i][son]<dp[i-1][j]+sum[son]){
dp[i][son]=dp[i-1][j]+sum[son];
from[i][son][0]=j;//record the source of the maximum value
from[i][son][1]=a[i]-'0';//record the corresponding character
}
}
else{//character is unfixed
for(k=0;k<10;k++){
son=ch[j][k];
if(dp[i][son]<dp[i-1][j]+sum[son]){
dp[i][son]=dp[i-1][j]+sum[son];
from[i][son][0]=j;
from[i][son][1]=k;
}
}
}
}
}
int pos=0;
for(i=1;i<=cntn;i++) if(dp[n][i]>dp[n][pos]) pos=i;
for(i=0;i<=cntn;i++) sum[i]+=mid*(double)num[i];//repair the value cut
endpos=pos;return dp[n][pos]>0;//determine if largest value is over zero
}
char re[1510];
int main(){
n=read();m=read();int i;
scanf("%s",a+1);
for(i=1;i<=m;i++){
scanf("%s",s[i]+1);
w[i]=read();
w[i]=log((double)w[i]);
insert(i,strlen(s[i]+1));
}
build();
double l=0,r=log(1e9+7),mid,ans=0;
while(r-l>1e-6){//binary search
mid=(l+r)*0.5;
if(check(mid)) ans=mid,l=mid;
else r=mid;
}
check(ans);
for(i=n;i>=1;i--){//get the answer string
re[i]=from[i][endpos][1]+'0';
endpos=from[i][endpos][0];
}
for(i=1;i<=n;i++) putchar(re[i]);
putchar('\n');
}

[BJOI2019] 奥术神杖 [取log+AC自动机+dp]的更多相关文章

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

    对最终答案取对数,得到$\ln(Ans)=\frac{1}{c}\sum \ln(v_i)$,典型的分数规划问题.二分答案后,对所有咒语串建立AC自动机,然后套路地$f[i][j]$表示走到T的第i个 ...

  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. [BJOI2019]奥术神杖(分数规划,动态规划,AC自动机)

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

  5. 【hdu2457】ac自动机 + dp

    传送门 题目大意: 给你一个字符主串和很多病毒串,要求更改最少的字符使得没有一个病毒串是主串的子串. 题解: ac自动机 + dp,用病毒串建好ac自动机,有毒的末尾flag置为true 构建fail ...

  6. 2021.11.11 P4052 [JSOI2007]文本生成器(AC自动机+DP)

    2021.11.11 P4052 [JSOI2007]文本生成器(AC自动机+DP) https://www.luogu.com.cn/problem/P4052 题意: JSOI 交给队员 ZYX ...

  7. POJ1625 Censored!(AC自动机+DP)

    题目问长度m不包含一些不文明单词的字符串有多少个. 依然是水水的AC自动机+DP..做完后发现居然和POJ2778是一道题,回过头来看都水水的... dp[i][j]表示长度i(在自动机转移i步)且后 ...

  8. HDU2296 Ring(AC自动机+DP)

    题目是给几个带有价值的单词.而一个字符串的价值是 各单词在它里面出现次数*单词价值 的和,问长度不超过n的最大价值的字符串是什么? 依然是入门的AC自动机+DP题..不一样的是这题要输出具体方案,加个 ...

  9. HDU2457 DNA repair(AC自动机+DP)

    题目一串DNA最少需要修改几个基因使其不包含一些致病DNA片段. 这道题应该是AC自动机+DP的入门题了,有POJ2778基础不难写出来. dp[i][j]表示原DNA前i位(在AC自动机上转移i步) ...

随机推荐

  1. CF1163E Magical Permutation【线性基,构造】

    题目描述:输入一个大小为\(n\)的正整数集合\(S\),求最大的\(x\),使得能构造一个\(0\)到\(2^x-1\)的排列\(p\),满足\(p_i\oplus p_{i+1}\in S\) 数 ...

  2. Three.js中的group,obj,模型中layers层级与相机

    目录 Three.js中的group,obj,模型中layers层级与相机 layers group中的.layers.mask设置 一些设想 Three.js中的group,obj,模型中layer ...

  3. CF891C Envy(离线/在线+可撤销并查集/并查集/LCT)

    前置知识 最小生成树及证明 做法 每个不同权值没影响,仅需判断该次询问每种权值是否在"小于该权值的所有边加完"之后,可以全部加进来 离线:询问的所有边全堆到一起,按权值排序,然后同 ...

  4. 中山纪中集训Day5叒是测试(划淼)

    A组T1 矩阵游戏(game) 九校联考24OI__D1T1 问题描述 LZK发明一个矩阵游戏,大家一起来玩玩吧,有一个N行M列的矩阵.第一行的数字是1,2,…M,第二行的数字是M+1,M+2…2*M ...

  5. css自定义属性和简单效果

    简介 CSS Variables,一个并不是那么新的东西,但对css来说绝对是一场革命. 之前使用变量的时候,需要借助sass.less等预处理工具来实现,现在我们可以直接使用css来声明变量. 兼容 ...

  6. 2018-2019-2 网络对抗技术 20165212 Exp 8 Web基础

    2018-2019-2 网络对抗技术 20165212 Exp 8 Web基础 原理与实践说明 1.实践内容概述 1.Web前端HTML 能正常安装.启停Apache.理解HTML,理解表单,理解GE ...

  7. sql server 自增列,值突然增大1000的情况

    sql server 自增列,值突然增大1000的情况   解决方法: 1 打开配置管理器2左面点击sql服务3右面 右键点击SQL Server(MSSQLSERVER) 4点击 启动参数5 在参数 ...

  8. C# ffmpeg 视频处理

    ffmpeg的官网:https://ffmpeg.org/ ffmpeg是一个强大的视频处理软件(控制台程序),可以通过C# 调用ffmpeg,并传入指令参数,即可实现视频的编辑. /// <s ...

  9. [原]Arcgis arcmap修改图元配色

    感谢南师大的“深爱”提供的帮助 1.选择识别工具,点击海洋,确定海洋色块的color index为255 2.右键tif选择属性 3.选择分页栏中的符号化(Symbology) 4.找到对应的Labe ...

  10. 001-guava概述

    一.概述 Guava工程包含了若干被Google的 Java项目广泛依赖 的核心库,例如:集合 [collections] .缓存 [caching] .原生类型支持 [primitives supp ...