传送门


problem

神杖上从左到右镶嵌了 n n n 颗奥术宝石,奥术宝石一共有 10 10 10 种,用数字 “ 0123456789 ” “0123456789” “0123456789” 表示。有些位置的宝石已经残缺,用 “ . ” “.” “.” 表示,你需要用完好的奥术宝石填补每一处残缺的部分(每种奥术宝石个数不限,且不能够更换未残缺的宝石)。古老的魔法书上记载了 m m m 种咒语 ( S i , V i ) (S_i,V_i) (Si​,Vi​),其中 S i S_i Si​ 是一个非空数字串, V i V_i Vi​ 是这种组合能够激发的神力。

神杖的初始神力值 Magic=1 \texttt{Magic=1} Magic=1,每当神杖中出现了连续一段宝石与 S i S_i Si​ 相等时,神力值 Magic \texttt{Magic} Magic 就会乘以 V i V_i Vi​。但神杖如果包含了太多咒语就不再纯净导致神力降低:设 c c c 为神杖包含的咒语个数(若咒语类别相同但出现位置不同视为多次),神杖最终的神力值为 Magic c \sqrt[c]{\texttt{Magic}} cMagic ​ 。(若 c = 0 c=0 c=0 则神杖最终神力值为 1 1 1。)

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

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

数据范围: 1 ≤ m ≤ 1501 1≤m≤1501 1≤m≤1501, 1 ≤ V i ≤ 1 0 9 1≤V_i≤10^9 1≤Vi​≤109。


solution

由于这是多个串的匹配问题,AC 自动机是少不了的,先把它建出来再说。

现在分析题目,假设串中有 c c c 个咒语,每个咒语的权值分别为 w i w_i wi​,那么魔法值就是 Magic = ∏ i = 1 c w i c \texttt{Magic}=\sqrt[c]{\prod_{i=1}^cw_i} Magic=c∏i=1c​wi​ ​。

我们两边取对数,把根号消掉,得到 ln ⁡ Magic = 1 c ∑ i = 1 c ln ⁡ w i \ln\texttt{Magic}=\frac 1 c\sum_{i=1}^c\ln w_i lnMagic=c1​∑i=1c​lnwi​。

由于我们只用比较 Magic \texttt{Magic} Magic 的相对大小,并不需要知道 Magic \texttt{Magic} Magic 具体的值,可以在一开始就对 w i w_i wi​ 取对数,最大化 1 c ∑ i = 1 c ln ⁡ w i \frac 1 c\sum_{i=1}^c \ln w_i c1​∑i=1c​lnwi​。

比较显然的是可以 0 / 1 0/1 0/1 分数规划,设当前二分到的答案是 λ \lambda λ,则:

1 c ∑ i = 1 c ln ⁡ w i > λ ∑ i = 1 c ( ln ⁡ w i − λ ) > 0 \begin{aligned}\frac 1 c\sum_{i=1}^c\ln w_i&>\lambda\\\sum_{i=1}^c(\ln w_i-\lambda)&>0\end{aligned} c1​i=1∑c​lnwi​i=1∑c​(lnwi​−λ)​>λ>0​

也就是说,我们把小串的权值改成 ln ⁡ w i − λ \ln w_i-\lambda lnwi​−λ,然后在自动机上 d p dp dp,看是否存在一种权值 > 0 >0 >0 的走法即可。

具体来说就是设 f [ i ] [ j ] f[i][j] f[i][j] 表示已经遍历了神杖上前 i i i 个字符,且当前在自动机的节点 j j j 的最大权值。那么只需枚举下一步怎么走然后转移即可(如果 i + 1 i+1 i+1 已经固定了那就只有 1 1 1 种走法)。

PS:代码实现稍微有点不一样,但是大体思路就是这样。


code

#include<bits/stdc++.h>
#define N 2005
#define eps 1e-6
using namespace std;
typedef pair<int,int> pii;
int n,m,tot,c[N][N],edge[N][N];
double f[N][N],v;
struct Trie{double val;int num,fail,son[26];
}T[N];
char S[N],a[N];
void Insert(){int p=0,l=strlen(a+1);for(int i=1;i<=l;++i){int x=a[i]-'0';if(!T[p].son[x])  T[p].son[x]=++tot;p=T[p].son[x];}++T[p].num,T[p].val=v;
}
queue<int>Q;
void Get_fail(){for(int i=0;i<10;++i)if(T[0].son[i])  Q.push(T[0].son[i]);while(!Q.empty()){int x=Q.front();Q.pop();T[x].num+=T[T[x].fail].num;T[x].val+=T[T[x].fail].val;for(int i=0;i<10;++i){if(T[x].son[i]){Q.push(T[x].son[i]);T[T[x].son[i]].fail=T[T[x].fail].son[i];}else  T[x].son[i]=T[T[x].fail].son[i];}}
}
bool check(double mid){memset(f,-0x3f,sizeof(f));f[0][0]=0;for(int i=1;i<=n;++i){for(int j=0;j<=tot;++j){if(S[i]=='.'){for(int k=0;k<10;++k){int to=T[j].son[k];double tmp=f[i-1][j]+T[to].val-mid*T[to].num;if(tmp>f[i][to])  f[i][to]=tmp,c[i][to]=k,edge[i][to]=j;}}else{int to=T[j].son[S[i]-'0'];double tmp=f[i-1][j]+T[to].val-mid*T[to].num;if(tmp>f[i][to])  f[i][to]=tmp,edge[i][to]=j;}}}for(int i=0;i<=tot;++i)  if(f[n][i]>eps)  return true;return false;
}
void Get(int x,int to){if(!x)  return;if(S[x]=='.')  S[x]=c[x][to]+'0';Get(x-1,edge[x][to]);
}
int main(){scanf("%d%d%s",&n,&m,S+1);for(int i=1;i<=m;++i){scanf("%s%lf",a+1,&v);v=log(v),Insert();}Get_fail();double l=0,r=100;while(r-l>eps){double mid=(l+r)/2;if(check(mid))  l=mid;else  r=mid;}check(l);for(int i=0;i<=tot;++i)  if(f[n][i]>eps)  {Get(n,i);break;}printf("%s\n",S+1);return 0;
}

「BJOI 2019」奥术神杖相关推荐

  1. 「BJOI 2019」勘破神机

    传送门 problem 经过了一个月的艰苦尝试,你的研究团队破译了 "2""2""2" 型奥术宝石和 "3"" ...

  2. 【BJOI 2019】奥术神杖

    题意 你有一个长度为 $n$ 的模板串(由 $0-9$ 这 $10$ 个数字和通配符 $.$ 组成),还有 $m$ 个匹配串(只由 $0-9$ 这 $10$ 个数字组成),每个匹配串有一个魔力值 $v ...

  3. 「BJOI 2019」排兵布阵

    传送门 problem 小 C 正在玩一款排兵布阵的游戏.在游戏中有 nnn 座城堡,每局对战由两名玩家来争夺这些城堡.每名玩家有 mmm 名士兵,可以向第 iii 座城堡派遣 aia_iai​ 名士 ...

  4. Loj #3089. 「BJOI2019」奥术神杖

    Loj #3089. 「BJOI2019」奥术神杖 题目描述 Bezorath 大陆抵抗地灾军团入侵的战争进入了僵持的阶段,世世代代生活在 Bezorath 这片大陆的精灵们开始寻找远古时代诸神遗留的 ...

  5. LOJ#3054. 「HNOI 2019」鱼

    LOJ#3054. 「HNOI 2019」鱼 https://loj.ac/problem/3054 题意 平面上有n个点,问能组成几个六个点的鱼.(n<=1000) 分析 鱼题,劲啊. 容易想 ...

  6. #3144. 「APIO 2019」奇怪装置

    #3144. 「APIO 2019」奇怪装置 题目描述 考古学家发现古代文明留下了一种奇怪的装置.该装置包含两个屏幕,分别显示两个整数 \(x\) 和 \(y\). 经过研究,科学家对该装置得出了一个 ...

  7. 「BJOI2019」奥术神杖(AC自动机+DP)

    文章目录 title solution code title solution 令Magic=Vi×Vj×Vk...Magic=V_i\times V_j\times V_k...Magic=Vi​× ...

  8. 【LOJ #6617】「THUPC 2019」摆家具 / furniture(DP / BSGS / 矩阵快速幂)

    传送门 首先显然k=lognk=lognk=logn 显然对于每个iii我们只用关注有多少位与询问的数字不同 考虑分成两个部分 先对每个数字iii求出与他有jjj位不同的数字价值之和 再求出ttt轮后 ...

  9. 「CSP-S 2019」 Emiya 家今天的饭 题解

    题面 样例 2 3 1 0 1 0 1 1 3 分析 考虑正着限制最大的数不超过一半不好做,那我们可以反着来. 令 dp[i][j][k]dp[i][j][k]dp[i][j][k] 为第 iii 行 ...

最新文章

  1. LOJ 2537 「PKUWC2018」Minimax
  2. oracle判断非空并拼接,oracle sql 判断字段非空,数据不重复,插入多跳数据
  3. 部署Laravel项目到centos服务器上
  4. [YTU]_2613( 距离产生美)
  5. 【c++】22. STL容器的底层实现详解
  6. hdu1009 - 贪心
  7. 模拟k8s项目的生命周期
  8. 好书推荐 -《国富论》-15-09
  9. 嵌入式Linux多任务编程 进程 管道 命名管道
  10. 在自己的电脑上搭建服务器(可供对外访问)
  11. java----内省
  12. SVN 下载与安装(超简单)!!!
  13. 安装Alfa Awus 1900 驱动到 Kali Linux
  14. 一定要学会了解大数据
  15. 初学者如何入门C语言
  16. 非常有意思的网页版在线PS
  17. Linux 调试之 TRACE_EVENT(三)
  18. 几种常见的线程池及使用场景
  19. 怎么计算机械设备电机,电机功率计算公式是什么?电机正确选配方法
  20. [GBase 8s 教程]GBase 8s ALTER TABLE 命令

热门文章

  1. ACM数论 裴蜀定理(贝祖定理)
  2. Spring Security系列教程11--Spring Security核心API讲解
  3. Zigzag和蛇形矩阵
  4. 最新版阿里巴巴Java开发手册(嵩山版)-附免费下载链接
  5. 省市区三级级联JSON解析打印各级key及value
  6. Mysql优化算法-MRR(Multi-Range Read Optimization)
  7. 汉画轩—让国学与区块链技术碰撞出更璀璨的火花
  8. 去掉字符串中的所有空格
  9. 【Java基础】JDK9 模块化
  10. 51单片机c语言程序控制,51单片机C语言程序设计源代码