「BJOI2019」奥术神杖

「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}$。

你需要使修复好的神杖的最终的神力值最大,输出任何一个解即可。



Sol

考虑对贡献取对数,则乘变成加,根号变成/n。

那么问题转化为0/1分数规划。

建AC自动机,把每一个点的贡献减去ans,若存在一种填字方案使得总代价>0,那么合法。

这部分可以dp实现.令f[i][j]表示当前走到ac自动机上节点i,已经匹配前j位的最大收益。

效率O(n^2logn)

ac自动机建fail时需要转移,把fail[i]的信息加到i上.

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define db double
#define maxn 3005
#define eps 1e-3
#define inf 1e9
using namespace std;
int n,m,tr[maxn][10],fail[maxn],num[maxn],tot,g[maxn][maxn],b[maxn][maxn];
double v[maxn],c[maxn],f[maxn][maxn];
char T[maxn],s[maxn];
void ins(int val){
    int k=0,len=strlen(s+1);
    for(int i=1;i<=len;i++){
        if(!tr[k][s[i]-‘0‘])tr[k][s[i]-‘0‘]=++tot;
        k=tr[k][s[i]-‘0‘];
    }
    num[k]++;v[k]+=log(val);
}
void build(){
    queue<int>q;
    for(int i=0;i<10;i++)if(tr[0][i])q.push(tr[0][i]);
    while(!q.empty()){
        int k=q.front();q.pop();
        num[k]+=num[fail[k]];
        v[k]+=v[fail[k]];
        for(int i=0;i<10;i++){
            if(tr[k][i])fail[tr[k][i]]=tr[fail[k]][i],q.push(tr[k][i]);
            else tr[k][i]=tr[fail[k]][i];
        }
    }
}
db work(int k,int p){
    if(g[k][p])return f[k][p];
    if(p==n+1){g[k][p]=1;f[k][p]=c[k];return f[k][p];}
    if(T[p]==‘.‘){
        f[k][p]=-inf;
        for(int i=0;i<10;i++){
            db x=work(tr[k][i],p+1);
            if(x>f[k][p])f[k][p]=x,b[k][p]=i;
        }
    }
    else f[k][p]=work(tr[k][T[p]-‘0‘],p+1);
    g[k][p]=1;f[k][p]+=c[k];
    return f[k][p];
}
bool pd(db val){
    for(int i=1;i<=tot;i++){
        c[i]=v[i]-num[i]*val;
    }
    db tmp=work(0,1);
    for(int i=0;i<=tot;i++)
    for(int j=1;j<=n+1;j++)g[i][j]=0;
    return tmp>0;
}
void outp(){
    int k=0;
    for(int i=1;i<=n;i++){
        if(T[i]==‘.‘)printf("%d",b[k][i]),k=tr[k][b[k][i]];
        else printf("%c",T[i]),k=tr[k][T[i]-‘0‘];
    }
    puts("");
}
int main(){
    cin>>n>>m;
    scanf(" %s",T+1);
    for(int i=1,val;i<=m;i++){
        scanf(" %s",s+1);scanf("%d",&val);
        ins(val);
    }
    build();
    db l=0,r=20;
    while(l+eps<r){
        db mid=(l+r)/2;
        if(pd(mid))l=mid;
        else r=mid;
    }

    pd(l);outp();
    return 0;
}

原文地址:https://www.cnblogs.com/liankewei/p/12237561.html

时间: 2024-10-09 07:00:26

「BJOI2019」奥术神杖的相关文章

dtoi4375「BJOI2019」删数

题意: 对于任意一个数列,如果能在有限次进行下列删数操作后将其删为空数列,则称这个数列可以删空.一次删数操作定义如下: 记当前数列长度为 k,则删掉数列中所有等于 k 的数. 现有一个长度为 n 的数列 a,有 m 次修改操作,第 i 次修改后你要回答:经过 i 次修改后的数列 a,至少还需要修改几个数才可删空? 每次修改操作为单点修改或数列整体加一或数列整体减一. 题解:      如果一个我要删去大小为a的数,那么序列长度会变成a-h[a](h[a]为数值a出线的次数).那么我们意会一下这个

[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$自动机上的$D

[LuoguP5319] [BJOI2019] 奥术神杖 (01分数规划+AC自动机+dp)

[LuoguP5319] [BJOI2019] 奥术神杖 (01分数规划+AC自动机+dp) 题面 神杖上从左到右镶嵌了\(n\)颗奥术宝石,奥术宝石一共有 1010 种,用数字 0123456789 表示.有些位置的宝石已经残缺,用 . 表示,你需要用完好的奥术宝石填补每一处残缺的部分(每种奥术宝石个数不限,且不能够更换未残缺的宝石).古老的魔法书上记载了 \(m\) 种咒语 \((S_i,V_i)\),其中 \(S_i\)是一个非空数字串,\(V_i\)是这种组合能够激发的神力. 神杖的初始

AC日记——「HNOI2017」单旋 LiBreOJ 2018

#2018. 「HNOI2017」单旋 思路: set+线段树: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 100005 #define maxtree maxn<<2 int val[maxtree],tag[maxtree],L[maxtree],R[maxtree],mid[maxtree]; int op[maxn],ki[maxn],bi[maxn],cnt,size,n,ch[maxn]

「随笔」基于当下的思考

马德,说好的技术blog,变成日记本了... 下午的时候莫名其妙的感到很颓废,因为自己的不够强大感到忧虑和危机感十足.现在每每行走在技术的道路上,常觉得如履薄冰,如芒在背. 上大学之前和现在的心态其实差别挺大的,视野的开阔远远不止局限于自己的脚下.不过,这里的「上大学之前」只是一个时间描述词,并不觉得大学是最适合学习的地方,我很失望. 世界上的人无论性别,区域,宗教,兴趣爱好,总可以在互联网上找到志趣相同的人,总是可以不断打破自己的常识与惯性思维.总是有在相同领域比自己更强的人,挺好的. 关于知

「Unity」与iOS、Android平台的整合:3、导出的Android-Studio工程

本文属于「Unity与iOS.Android平台的整合」系列文章之一,转载请注明出处. Unity默认导出的是Android-Eclipse工程,毕竟Eclipse for Android开发在近一两年才开始没落,用户量还是非常巨大的. 个人认为AndroidStudio非常好用,能轻易解决很多Eclipse解决不了或者很难解决的问题. 所以我将Unity导出的Andoid工程分为Eclipse和AndroidStudio两部分. 不过我之后的相关内容都会使用AndroidStudio,希望依然

大数据和「数据挖掘」是何关系?---来自知乎

知乎用户,互联网 244 人赞同 在我读数据挖掘方向研究生的时候:如果要描述数据量非常大,我们用Massive Data(海量数据)如果要描述数据非常多样,我们用Heterogeneous Data(异构数据)如果要描述数据既多样,又量大,我们用Massive Heterogeneous Data(海量异构数据)--如果要申请基金忽悠一笔钱,我们用Big Data(大数据) 编辑于 2014-02-2817 条评论感谢 收藏没有帮助举报作者保留权利 刘知远,NLPer 4 人赞同 我觉得 大数据

开放的智力8:实用「成功学」

可实现的「成功学」 现在我想为这里的年轻人介绍一种可实现的「成功学」.希望这个我自创的理论,可以改变很多人的一生. 当我们评价一个事情值不值得去做.应该花多少精力去做的时候,应该抛弃单一的视角,而是分两个不同的维度来看,一是该事件将给我带来的收益大小(认知.情感.物质.身体方面的收益皆可计入),即「收益值」:二是该收益随时间衰减的速度,我称为「收益半衰期」,半衰期长的事件,对我们的影响会持续得较久较长. 这两个维度正交以后就形成了一个四象限图.我们生活.学习和工作中的所有事情都可以放进这个图里面

Linux 小知识翻译 - 「syslog」

这次聊聊「syslog」. 上次聊了「日志」(lgo).这次说起syslog,一看到log(日志)就明白是怎么回事了.syslog是获取系统日志的工具. 很多UINIX系的OS都采用了这个程序,它承担了「获取系统全部的日志」这个维持系统正常运行的重要任务. syslog的本体是「syslogd」这个daemon(一般翻译成守护进程),常驻内存中获取日志. syslog的特点是可以通过配置文件「/etc/syslog.conf」,对「哪种应用程序?哪种重要度的信息?记录在哪个文件中?」等进行细致的