Loj #3089. 「BJOI2019」奥术神杖

题目描述

Bezorath 大陆抵抗地灾军团入侵的战争进入了僵持的阶段,世世代代生活在 Bezorath 这片大陆的精灵们开始寻找远古时代诸神遗留的神器,试图借助神器的神秘

力量帮助她们战胜地灾军团。

在付出了惨痛的代价后,精灵们从步步凶险的远古战场取回了一件保存尚完好的神杖。但在经历过那场所有史书都视为禁忌的“诸神黄昏之战”后,神杖上镶嵌的奥术宝石

已经残缺,神力也几乎消耗殆尽。精灵高层在至高会议中决定以举国之力收集残存至今的奥术宝石,并重金悬赏天下能工巧匠修复这件神杖。

你作为神术一脉第五百零一位传人,接受了这个艰巨而神圣的使命。 神杖上从左到右镶嵌了 \(n\) 颗奥术宝石,奥术宝石一共有 \(10\) 种,用数字 0123456789

表示。有些位置的宝石已经残缺,用 . 表示,你需要用完好的奥术宝石填补每一处残缺的部分(每种奥术宝石个数不限,且不能够更换未残缺的宝石)。古老的魔法

书上记载了 \(m\) 种咒语 \((S_i,V_i)\),其中 \(S_i\) 是一个非空数字串,\(V_i\) 是这种组合能够激发的神力。

神杖的初始神力值 \(\mathrm{Magic} = 1\),每当神杖中出现了连续一段宝石与 \(S_i\) 相等时,神力值 \(\mathrm{Magic}\) 就会乘以 \(V_i\)。但神杖如果包含

了太多咒语就不再纯净导致神力降低:设 \(c\) 为神杖包含的咒语个数(若咒语类别相同但出现位置不同视为多次),神杖最终的神力值为 \(\sqrt[c]{\mathrm{Magic}}\)。(若 \(c = 0\) 则神杖最终神力值为 \(1\)。)

例如有两种咒语 \((01,3)\) 、\((10,4)\),那么神杖 0101 的神力值为 \(\sqrt[3]{ 3 \times 4 \times 3}\)。

输入格式

第一行两个正整数 \(n,m\),表示宝石数和咒语数。

第二行为一个长度为 \(n\) 的字符串 \(T\),表示初始的神杖。

接下来 \(m\) 行每行一个非空数字串 \(S_i\) 和一个正整数 \(V_i\),表示每种咒语。

输出格式

输出最终神杖上从左到右镶嵌的宝石,多解时任意输出一个即可。

数据范围与提示

\(n,\sum_{i=1}^m|S_i|\leq 150\)。\(V_i\leq 10^9\)

\(\\\)

首先将答案取一个对数,

\[\displaystyle
\log_2^{\sqrt[c]{\prod_{i=1}^c V_i}}=\frac{\sum_{i=1}^c\log_2^{V_i}}{c}
\]

要求最大化\(\frac{\sum_{i=1}^c V_i}{c}\)就是裸的\(0/1\)分数规划问题(我竟然没看出来,真是越来越zz了)。具体实现时在\(AC\)自动机上\(DP\)就好了。

代码:

#include<bits/stdc++.h>
#define ll long long
#define N 1505
#define eps 1e-8 using namespace std;
inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;} int n,m;
char s[N],t[N]; struct trie {
int ch[10];
int cnt,fail;
double sum;
}tr[N]; int cnt=1;
void Insert(char *s,double val) {
int len=strlen(s+1);
int v=1;
for(int i=1;i<=len;i++) {
int j=s[i]-'0';
if(!tr[v].ch[j]) tr[v].ch[j]=++cnt;
v=tr[v].ch[j];
}
tr[v].cnt++;
tr[v].sum+=val;
} void build_fail() {
static queue<int>q;
for(int i=0;i<10;i++) {
if(!tr[1].ch[i]) tr[1].ch[i]=1;
else {
tr[tr[1].ch[i]].fail=1;
q.push(tr[1].ch[i]);
}
}
while(!q.empty()) {
int v=q.front();
q.pop();
tr[v].cnt+=tr[tr[v].fail].cnt;
tr[v].sum+=tr[tr[v].fail].sum;
for(int i=0;i<10;i++) {
if(!tr[v].ch[i]) tr[v].ch[i]=tr[tr[v].fail].ch[i];
else {
int sn=tr[v].ch[i];
tr[sn].fail=tr[tr[v].fail].ch[i];
q.push(sn);
}
}
}
} double f[N][N];
double tag[N];
struct node {
int x,y,type;
node() {}
node(int _x,int _y,int _type) {
x=_x,y=_y,type=_type;
}
}; node fr[N][N];
bool chk(double ans) {
for(int i=1;i<=cnt;i++) tag[i]=tr[i].sum-tr[i].cnt*ans;
for(int i=0;i<=n;i++)
for(int j=1;j<=cnt;j++)
f[i][j]=-1e9;
f[0][1]=0;
for(int i=0;i<n;i++) {
for(int j=1;j<=cnt;j++) {
if(f[i][j]<-1e6) continue ;
if(s[i+1]=='.') {
for(int k=0;k<10;k++) {
int q=tr[j].ch[k];
if(f[i][j]+tag[q]>f[i+1][q]) {
f[i+1][q]=f[i][j]+tag[q];
fr[i+1][q]=node(i,j,k);
}
}
} else {
int q=tr[j].ch[s[i+1]-'0'];
if(f[i][j]+tag[q]>f[i+1][q]) {
f[i+1][q]=f[i][j]+tag[q];
fr[i+1][q]=node(i,j,s[i+1]-'0');
}
}
}
}
for(int i=1;i<=cnt;i++) if(f[n][i]>0) return 1;
return 0;
} void out(int x,int y) {
if(!x) return ;
out(fr[x][y].x,fr[x][y].y);
cout<<fr[x][y].type;
} int main() {
n=Get(),m=Get();
scanf("%s",s+1);
for(int i=1;i<=m;i++) {
scanf("%s",t+1);
double v=Get();
Insert(t,log2(v));
}
build_fail();
double l=0,r=100,mid;
while(l+eps<r) {
mid=(l+r)/2.0;
if(chk(mid)) l=mid;
else r=mid-eps;
}
chk(l);
for(int i=1;i<=cnt;i++) {
if(f[n][i]>0) {
out(n,i);
break ;
}
}
return 0;
}

Loj #3089. 「BJOI2019」奥术神杖的更多相关文章

  1. LOJ 3089 「BJOI2019」奥术神杖——AC自动机DP+0/1分数规划

    题目:https://loj.ac/problem/3089 没想到把根号之类的求对数变成算数平均值.写了个只能得15分的暴力. #include<cstdio> #include< ...

  2. 【LOJ】#3089. 「BJOI2019」奥术神杖

    LOJ#3089. 「BJOI2019」奥术神杖 看见乘积就取log,开根号就是除法,很容易发现这就是一道01分数规划.. 然后建出AC自动机直接dp就行,判断条件要设成>0,因为起点的值是1, ...

  3. LOJ 3089: 洛谷 P5319: 「BJOI2019」奥术神杖

    题目传送门:LOJ #3089. 题意简述: 有一个长度为 \(n\) 的母串,其中某些位置已固定,另一些位置可以任意填. 同时给定 \(m\) 个小串,第 \(i\) 个为 \(S_i\),所有位置 ...

  4. Loj #3093. 「BJOI2019」光线

    Loj #3093. 「BJOI2019」光线 题目描述 当一束光打到一层玻璃上时,有一定比例的光会穿过这层玻璃,一定比例的光会被反射回去,剩下的光被玻璃吸收. 设对于任意 \(x\),有 \(x\t ...

  5. loj 3090 「BJOI2019」勘破神机 - 数学

    题目传送门 传送门 题目大意 设$F_{n}$表示用$1\times 2$的骨牌填$2\times n$的网格的方案数,设$G_{n}$$表示用$1\times 2$的骨牌填$3\times n$的网 ...

  6. LOJ 3094 「BJOI2019」删数——角标偏移的线段树

    题目:https://loj.ac/problem/3094 弱化版是 AGC017C . 用线段树维护那个题里的序列即可. 对应关系大概是: 真实值的范围是 [ 1-m , n+m ] :考虑设偏移 ...

  7. LOJ 3090 「BJOI2019」勘破神机——斯特林数+递推式求通项+扩域

    题目:https://loj.ac/problem/3090 题解:https://www.luogu.org/blog/rqy/solution-p5320 1.用斯特林数把下降幂化为普通的幂次求和 ...

  8. LOJ 3093 「BJOI2019」光线——数学+思路

    题目:https://loj.ac/problem/3093 考虑经过种种反射,最终射下去的光线总和.往下的光线就是这个总和 * a[ i ] . 比如只有两层的话,设射到第二层的光线是 lst ,那 ...

  9. LOJ 3092 「BJOI2019」排兵布阵 ——DP

    题目:https://loj.ac/problem/3092 同一个人的不同城堡之间没有什么联系,只是和<=m.所以对每个城堡的 s 个值排序,做一个 f[ i ][ j ] 表示第 i 个城堡 ...

随机推荐

  1. gulp+tp5配置

    优化了文件过滤,更改文件只会重新生成修改的文件 项目目录构建: 在入口文件public下,创建html目录,作为前台静态资源目录 gulp.js文件 /*! * gulp * $ npm instal ...

  2. Python学习日记(一):拜见小主——Python

    近日学习Python,特将学习过程及一点心得记录于此. 由于之前做过一个Java爬虫的项目,虽然很长时间没有碰过爬虫,但是小郭同学有一颗不死的爬虫心,哈哈.最近在互联网上找一些电影的时候,有很多电影只 ...

  3. Fusion Log

    What is Fusion Log? Also known as the Fusion Log or Assembly Binding Log Viewer. This tool is instal ...

  4. echarts在tab切换时容器宽度设置为100%,只展示100px

    在 mychart.setOption(option); 后面加上 mychart.resize(); 即可

  5. python进程和线程(六)

    协程 协程,又称微线程,纤程.英文名Coroutine.顾名思义,协程是协作式的,也就是非抢占式的程序(线程是抢占式的).协程的关键字是yield,一看到这个就想到了生成器对不对?那就顺便回顾一下生成 ...

  6. docker+es+kibana和springboot中使用es

    本次和大家分享的主要是docker搭建es和springboot操作es的内容,也便于工作中或将来使用方便,因此从搭建es环境开始到代码插入信息到es中:主要节点如下: elasticsearch启动 ...

  7. LindDotNetCore~Aspect面向方面编程

    回到目录 Aspect面向方面编程 面向侧面的程序设计(aspect-oriented programming,AOP,又译作面向方面的程序设计.观点导向编程.剖面导向程序设计)是计算机科学中的一个术 ...

  8. java 并发多线程显式锁概念简介 什么是显式锁 多线程下篇(一)

    目前对于同步,仅仅介绍了一个关键字synchronized,可以用于保证线程同步的原子性.可见性.有序性 对于synchronized关键字,对于静态方法默认是以该类的class对象作为锁,对于实例方 ...

  9. 详解MySQL表空间以及ibdata1文件过大问题

    ibdata1文件过大 原因分析 ibdata1是一个用来构建innodb系统表空间的文件,关于系统表空间详细介绍参考MySQL官网文档 上面是一个数据库的ibdata1文件,达到了780多G,而且还 ...

  10. DS控件库 DS标签的另类用法之折叠展开

    某些场合下,可以通过动态设置DS标签的文本内容来输出不同的显示效果,以下是示例. 示例中的素材   示例资源文本 String1="<linkimg=E1><b>&l ...