[BJOI2019]奥术神杖——AC自动机+DP+分数规划+二分答案
题目链接:
[BJOI2019]奥术神杖
答案是$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;}}
}
转载于:https://www.cnblogs.com/Khada-Jhin/p/10772191.html
[BJOI2019]奥术神杖——AC自动机+DP+分数规划+二分答案相关推荐
- P5319-[BJOI2019]奥术神杖【0/1分数规划,AC自动机,dp】
正题 题目链接:https://www.luogu.com.cn/problem/P5319 题目大意 一个长度为nnn的串TTT,用0∼90\sim 90∼9填充所有的.... 然后给出mmm个串和 ...
- P1768-天路【负环,SPFA,01分数规划,二分答案】
正题 题目链接:https://www.luogu.org/problemnew/show/P1768 题目大意 求一条回路使得路上∑vi∑pi\frac{\sum v_i}{\sum p_i}∑pi ...
- [jzoj 4230] 淬炼神体{ 0/1分数规划+二分答案}
题目 Description 王仙女将你提供的答案填在<葵花宝典>上,突然,宝典发出耀眼的白光,一股强大的吸力瞬间将仙女吸入宝典中. 一阵眩晕过后,仙女发现自己来到了一个浮岛上,四周的半空 ...
- HDU 2296 Ring AC自动机 + DP
题意:给你n个模式串,每个模式串有一个得分,让你构造出一个长度为N之内且分数最高的文本串;输出字典序列最小的. 解题思路: AC自动机 + DP , 不过要输出字典序列最小,多开一个 一个三维字符串 ...
- uvalive4842(AC自动机+DP)
题意: 给出猴子打字时打某个字母的概率,猴子最多可以敲键盘m次,问得到的长度是m的单词包含模式串的概率. 思路: AC自动机+dp. 首先,我们用模式串构造一个AC自动机,用dp[i]][j]表示当前 ...
- bzoj 1030: [JSOI2007]文本生成器(AC自动机+DP)
1030: [JSOI2007]文本生成器 Time Limit: 1 Sec Memory Limit: 162 MB Submit: 5187 Solved: 2136 [Submit][St ...
- 【BZOJ】4861: [Beijing2017]魔法咒语 AC自动机+DP+矩阵快速幂
[题意]给定n个原串和m个禁忌串,要求用原串集合能拼出的不含禁忌串且长度为L的串的数量.(60%)n,m<=50,L<=100.(40%)原串长度为1或2,L<=10^18. [算法 ...
- [BJOI2019]奥术神杖(分数规划+AC自动机+DP)
题解:很显然可以对权值取对数,然后把几何平均值转为算术平均值,然后很显然是分数规划.先对每个模式串建立AC自动机,每个节点w[i],sz[i]分别表示以其为前缀的字符串,然后再二分最优解k,然后w[i ...
- 牛客 - Connie(AC自动机+dp/KMP+dp)
题目链接:点击查看 题目大意:给出一个匹配串 sss,现在问模式串 ttt 的期望得分.其中假设匹配串在模式串中的出现次数为 xxx,那么将得到 2x2^x2x 的分数 题目分析:涉及到了期望一开始还 ...
最新文章
- 使用神经网络生成抽象随机艺术
- 浅谈JDBC与ODBC的区别与应用
- 自动化测试工具的选择
- js调试微博登录案例
- 基于 Kyma 的企业级云原生应用的扩展案例分享
- numpy拼接_巧用numpy切分图片
- printf打印百分号%
- 攻克学习多线程时碰到的难题(zz)
- 003之MFCSocket异步编程(指针机制)
- 【OpenCV新手教程之十四】OpenCV霍夫变换:霍夫线变换,霍夫圆变换合辑
- python中execute函数_在excel中调用python函数
- 盲源分离(BSS)的学习总结(PCA、ICA)
- git 和gitHup工具笔记的详细教程
- JMeter Ramp-up 说明
- QQ聊天记录的相关代码
- python 微博_用python发微博
- C语言考试题库之填空题
- 树莓派开发ADC芯片CS1237(C语言和python库开发)
- loj534. 「LibreOJ Round #6」花团
- 如何用Python 求函数 y = sinx 在区间[0, pi/2]上的弧长