[BJOI2019]奥术神杖——AC自动机+DP+分数规划+二分答案
题目链接:
答案是$ans=\sqrt[c]{\prod_{i=1}^{c}v_{i}}=(\prod_{i=1}^{c}v_{i})^{\frac{1}{c}}$。
这样不大好求,我们将这个式子取$ln$,变成$ln\ ans=\frac{1}{c}\sum_{i=1}^{c}ln\ v_{i}$。
这显然是一个分数规划,每次二分一个答案$mid$,将每个串的权值都减去$mid$,那么只需要求最大价值是否大于$0$即可。
剩下的问题就是一个在$AC$自动机上的$DP$了,设$f[i][j]$表示在$AC$自动机上的点$j$,已经匹配的长度为$i$时的最大值,在$AC$自动机上转移即可。
在$DP$时还要记录一下每个状态从哪个点转移过来以便输出方案。
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const double eps=1e-5;
int end[2000];
double f[2000][2000];
int g[2000][2000];
int fail[2000];
int tr[2000][10];
int cnt;
double val[2000];
char ch[2000];
char s[2000];
int now;
int n,m;
int v;
double ans;
void build(char *ch,int v)
{
int len=strlen(ch);
now=0;
for(int i=0;i<len;i++)
{
int x=ch[i]-'0';
if(!tr[now][x])
{
tr[now][x]=++cnt;
}
now=tr[now][x];
}
end[now]++;
val[now]+=log(v);
}
void get_fail()
{
queue<int>q;
for(int i=0;i<=9;i++)
{
if(tr[0][i])
{
q.push(tr[0][i]);
}
}
while(!q.empty())
{
now=q.front();
q.pop();
val[now]+=val[fail[now]];
end[now]+=end[fail[now]];
for(int i=0;i<=9;i++)
{
if(tr[now][i])
{
fail[tr[now][i]]=tr[fail[now]][i];
q.push(tr[now][i]);
}
else
{
tr[now][i]=tr[fail[now]][i];
}
}
}
}
double DP(double mid)
{
for(int i=0;i<=n;i++)
{
for(int j=0;j<=cnt;j++)
{
f[i][j]=-1e9;
g[i][j]=0;
}
}
f[0][0]=0;
for(int i=0;i<n;i++)
{
for(int j=0;j<=cnt;j++)
{
if(f[i][j]>-1e9)
{
if(s[i+1]=='.')
{
for(int k=0;k<=9;k++)
{
if(f[i+1][tr[j][k]]<f[i][j]+val[tr[j][k]]-mid*end[tr[j][k]])
{
f[i+1][tr[j][k]]=f[i][j]+val[tr[j][k]]-mid*end[tr[j][k]];
g[i+1][tr[j][k]]=j;
}
}
}
else
{
int x=s[i+1]-'0';
if(f[i+1][tr[j][x]]<f[i][j]+val[tr[j][x]]-mid*end[tr[j][x]])
{
f[i+1][tr[j][x]]=f[i][j]+val[tr[j][x]]-mid*end[tr[j][x]];
g[i+1][tr[j][x]]=j;
}
}
}
}
}
double res=-1e9;
for(int i=0;i<=cnt;i++)
{
res=max(res,f[n][i]);
}
return res;
}
void print(int dep,int now)
{
if(!dep)
{
return ;
}
print(dep-1,g[dep][now]);
if(s[dep]!='.')
{
printf("%c",s[dep]);
return ;
}
else
{
for(int i=0;i<=9;i++)
{
if(tr[g[dep][now]][i]==now)
{
printf("%c",i+'0');
return ;
}
}
}
}
int main()
{
scanf("%d%d",&n,&m);
scanf("%s",s+1);
for(int i=1;i<=m;i++)
{
scanf("%s%d",ch,&v);
build(ch,v);
}
get_fail();
double l=0,r=22;
while(r-l>eps)
{
double mid=(l+r)/2;
if(DP(mid)>0)
{
l=mid;
ans=mid;
}
else
{
r=mid;
}
}
DP(ans);
for(int i=0;i<=cnt;i++)
{
if(f[n][i]>0)
{
print(n,i);
break;
}
}
}
[BJOI2019]奥术神杖——AC自动机+DP+分数规划+二分答案的更多相关文章
- 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\)填充所有的\(.\). 然后给出\( ...
- 【Luogu】P3705新生舞会(费用流+分数规划+二分答案)
题目链接 本来以为自己可以做出来,结果……打脸了 (貌似来wc立了好几个flag了,都没竖起来) 不过乱蒙能蒙出一个叫“分数规划”的东西的式子还是很开心的 观察$C=\frac{a_{1}+a_{2} ...
- [SDOI2017] 新生舞会 - 二分图最大权匹配,分数规划,二分答案
有一个二分图,每个部都有 \(n\) 个点,每条边有两个参数 \(a_e, b_e\),求一种匹配,使得 \(\sum a_i / \sum b_i\) 最大 Solution 显然的分数规划,考虑二 ...
- poj2728 生成树01分数规划 (二分答案)
给定整数序列a,b,求出下式的最大值 sum{ai*xi}/sum{bi*xi},xi=0|1 通俗来说,就是选出一些整数对(ai,bi),使得选出的a之和与选出的b之和商最大化 二分答案L,即选出的 ...
- hdu6070(分数规划/二分+线段树区间更新,区间最值)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=6070 题意: 给出一个题目提交序列, 从中选出一个正确率最小的子串. 选中的子串中每个题目当且仅当最 ...
- 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步)且后 ...
随机推荐
- SpringFramework5.0 @Indexed注解 简单解析
目录 使用场景 使用方法 原理说明 使用需注意点 案例说明 参考资料 纸上得来终觉浅 绝知此事要躬行 -陆游 最近在看SpringBoot核编程思想(核心篇),看到走向注解驱动编程这章,里面有讲解到: ...
- Linux 配置jdk vim和 Linux 基本操作
1下载jdk tar.gz 安装包(http://www.oracle.com/) 注意安装机器的Linux 是x86(32位)还是x64(64位)的 2使用tar -zxvf jdk.tar.gz解 ...
- 【es6】es6使用集锦
一.查找数组中是否包含某个元素 使用includes ,返回值为布尔值 arr.includes(searchElement, fromIndex): 解析:searchElement 查询元 ...
- FlowPortal BPM 设置部门分管
企业中可能会有多个副总,分别分管不同的部门,员工发起申请需要副总审批时,流程根据员工所在部门查找部门的分管副总进行审批. 比如A公司有两个副总张三和李四,张三分管行政部.市场部,李四分管研发部.采购部 ...
- web容器(weblogic、resin、tomcat、jboss对比)
WebLogic 12c Linux静默安装 weblogic11g 密码忘记解决方案 glassfish和tomcat各自的优势和劣势 Linux Resin4.0 安装配置(优质) 对比 . we ...
- KVM虚拟机高级设置——08 管理远程虚拟机
在搭建KVM环境——07 带GUI的Linux上安装KVM图形界面管理工具介绍了KVM图形化管理工具,这款工具除了可以管理本地KVM虚拟外,还可以管理远程KVM虚拟机. 输入113机器密码 输入yes ...
- Java与CC++交互JNI编程
哈哈,经过了前面几个超级枯燥的C.C++两语言的基础巩固之后,终于来了到JNI程序的编写了,还是挺不容易的,所以还得再接再厉,戒骄戒躁,继续前行!! 第一个JNI程序: JNI是一种本地编程接口.它允 ...
- zznu-oj-2117 : 我已经在路上了(求函数的原函数的字符串)--【暴力模拟题,花式模拟题,String大法好】
2117 : 我已经在路上了 时间限制:1 Sec 内存限制:256 MiB提交:39 答案正确:8 提交 状态 编辑 讨论区 题目描述 spring是不折不扣的学霸,那可是机房考研中的头号选手,不吹 ...
- 5 webpack-dev-server的常用命令参数--open --port 3000 --contentBase src --hot
--open 自动打开浏览器 --port 3000 指定端口3000 --contentBase src 内容的根路径 --hot 热重载,热更新.打补丁,实现浏览器的无刷新
- Mysql 随机获得表的几条记录
在做博客文章详情的时候,有一个拓展阅读的功能: 想法一:根据当前文章Id,写死两条链接,Id+1,Id-1,但是文章Id可能被删除,Id不连续,不可取.× 想法二:获得当前文章记录的前一条和后一条记录 ...