#loj3089 [BJOI2019]奥术神杖
卡精度好题
最关键的一步是几何平均数的\(ln\)等于所有数字取\(ln\)后的算术平均值
那么现在就变成了一个很裸的01分数规划问题,一个通用的思路就是二分答案
现在来考虑二分答案的底层怎么写
把所有串拉出来造ac自动机,那么ac自动机上一个点的权值就是
fail树上这个点到祖先的树链上的字符串的权值之和
那么接下来设\(f(i,j)\)表示决策到了第\(i\)个字符,走到自动机节点\(j\)的最大收益大力dp即可
由于我们不希望均值是0,因此额外记录下有没有匹配上模式串即可
二分完了之后把mid调成l重新跑一遍dp,不然你会跑出无解的情况导致输出错误的答案
有个函数叫log2,精度比log高,这样你就可以少二分几次了
// luogu-judger-enable-o2
// luogu-judger-enable-o2
// luogu-judger-enable-o2
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;const int N=4000;typedef long long ll;
typedef long double db;db mid;//const db eps=1e-8;
const db low_inf=-1e9;
int v[N<<1];int x[N<<1];int ct;int al[N];
db we[N];db sum[N];int num[N];int snum[N];
inline void add(int u,int V){
//printf("add %d %d\n",u,V);
v[++ct]=V;x[ct]=al[u];al[u]=ct;}
inline void pdfs(int u)
{
snum[u]+=num[u];
for(int i=al[u];i;i=x[i])
snum[v[i]]=snum[u],pdfs(v[i]);
}
inline void dfs(int u)
{
sum[u]+=we[u]-mid*num[u];
for(int i=al[u];i;i=x[i])
sum[v[i]]=sum[u],dfs(v[i]);
}
struct trie
{
int mp[N][12];int cnt;int fil[N];
inline int ins(int p,int c)
{return mp[p][c]=(mp[p][c])?mp[p][c]:++cnt;}
inline void build()
{
queue <int> q;
for(int i=1;i<=10;i++)
if(mp[1][i])fil[mp[1][i]]=1,q.push(mp[1][i]);
else mp[1][i]=1;
while(!q.empty())
{
int nw=q.front();q.pop();
for(int i=1;i<=10;i++)
if(mp[nw][i])fil[mp[nw][i]]=mp[fil[nw]][i],q.push(mp[nw][i]);
else mp[nw][i]=mp[fil[nw]][i];
}
for(int i=1;i<=cnt;i++)
if(fil[i])add(fil[i],i);
}
}tr;
struct data{int c;int lst;int pval;}fr[N][N];db dp[N][N];
char mde[N];int n;int m;char smde[N];int op[N];int hd;
inline void trans(int i,int j,int k)
{
int tw=tr.mp[j][k];
db tval=dp[i][j]+sum[tw];
if(tval>=dp[i+1][tw])
{
dp[i+1][tw]=tval;
fr[i+1][tw]=(data){k,j,fr[i][j].pval+snum[tw]};
}
}
inline void pritans()
{
db curmx=-0x3f3f3f3f;int st=-1;
for(int i=1;i<=tr.cnt;i++)
if(curmx<dp[n][i])
curmx=dp[n][i],st=i;
hd=0;
for(int i=n;i>=1;i--)
op[++hd]=fr[i][st].c,st=fr[i][st].lst;
for(int i=n;i>=1;i--)
printf("%d",op[i]-1);
printf("\n");
}
inline bool jud()
{
//for(int i=1;i<=tr.cnt;i++)
// printf("%.3Lf ",sum[i]);printf("\n");
sum[1]=0;
dfs(1);
for(int i=0;i<=n;i++)
for(int j=1;j<=tr.cnt;j++)
dp[i][j]=-0x3f3f3f3f;
dp[0][1]=0;
for(int i=0;i<n;i++)
for(int j=1;j<=tr.cnt;j++)
{
if(dp[i][j]<low_inf)continue;
if(mde[i+1]=='.')
for(int k=1;k<=10;k++)
trans(i,j,k);
else
trans(i,j,mde[i+1]-'0'+1);
}
db mx=-0x3f3f3f3f;
for(int i=1;i<=tr.cnt;i++)
if(fr[n][i].pval)mx=max(mx,dp[n][i]);
//printf("mx=%.10Lf\n",mx);
// pritans();
return mx>=0;
}
int main()
{
//printf("%.10lf\n",exp(log(10)));
scanf("%d%d",&n,&m);
scanf("%s",mde+1);
tr.cnt=1;
for(int i=1,tmp;i<=m;i++)
{
scanf("%s",smde+1);
int p=1;
for(int j=1;smde[j]!='\0';j++)
p=tr.ins(p,smde[j]-'0'+1);
scanf("%d",&tmp);
we[p]+=log2(tmp);num[p]++;
// printf("%.10Lf\n",we[p]);
}
tr.build();
pdfs(1);
db l=0;db r=log2(1e9);
for(int i=1;i<=18;i++)
{
// printf("%.10Lf %.10Lf\n",l,r);
mid=(l+r)/2;
if(jud())l=mid;else r=mid;
}
mid=l;
jud();
pritans();
return 0;
}
#loj3089 [BJOI2019]奥术神杖的更多相关文章
- [BJOI2019]奥术神杖(分数规划,动态规划,AC自动机)
[BJOI2019]奥术神杖(分数规划,动态规划,AC自动机) 题面 洛谷 题解 首先乘法取\(log\)变加法,开\(c\)次根变成除\(c\). 于是问题等价于最大化\(\displaystyle ...
- [BJOI2019]奥术神杖——AC自动机+DP+分数规划+二分答案
题目链接: [BJOI2019]奥术神杖 答案是$ans=\sqrt[c]{\prod_{i=1}^{c}v_{i}}=(\prod_{i=1}^{c}v_{i})^{\frac{1}{c}}$. 这 ...
- luoguP5319 [BJOI2019]奥术神杖(分数规划,AC自动机DP)
luoguP5319 [BJOI2019]奥术神杖(分数规划,AC自动机DP) Luogu 题解时间 难点在于式子转化,设有c个满足的子串,即求最大的 $ ans = \sqrt[c]{\prod_{ ...
- 【题解】Luogu P5319 [BJOI2019]奥术神杖
原题传送门 题目让我们最大化\(val=\sqrt[k]{\prod_{i=1}^k w_i}\),其中\(k\)是咒语的个数,\(w_i\)是第\(i\)个咒语的神力 看着根号和累乘不爽,我们两边同 ...
- [BJOI2019]奥术神杖
https://www.luogu.org/problemnew/show/P5319 题解 首先观察我们要求的答案的形式: \[ \biggl(\prod V_i \biggr)^x\ \ \ x= ...
- [BJOI2019]奥术神杖(分数规划+AC自动机+DP)
题解:很显然可以对权值取对数,然后把几何平均值转为算术平均值,然后很显然是分数规划.先对每个模式串建立AC自动机,每个节点w[i],sz[i]分别表示以其为前缀的字符串,然后再二分最优解k,然后w[i ...
- luogu P5319 [BJOI2019]奥术神杖
传送门 要求的东西带个根号,这玩意叫几何平均数,说到平均数,我们就能想到算术平均数(就是一般意义下的平均数),而这个东西是一堆数之积开根号,所以如果每个数取对数,那么乘法会变成加法,开根号变成除法,所 ...
- [BJOI2019]奥术神杖(AC自动机,DP,分数规划)
题目大意: 给出一个长度 $n$ 的字符串 $T$,只由数字和点组成.你可以把每个点替换成一个任意的数字.再给出 $m$ 个数字串 $S_i$,第 $i$ 个权值为 $t_i$. 对于一个替换方案,这 ...
- [BJOI2019] 奥术神杖 [取log+AC自动机+dp]
题面 传送门 思路 首先,看到这个乘起来开根号的形式,应该能想到用取$\log$的方式做一个转化: $\sqrt[n]{\prod_i a_i}=\frac{1}{n}\sum_i \log_b a_ ...
随机推荐
- 494. Target Sum - Unsolved
https://leetcode.com/problems/target-sum/#/description You are given a list of non-negative integers ...
- ServiceDesk Plus解析内容,简化工单管理
- 粒子跟随本体unity
Simulation Space(模拟空间):在世界坐标和本地坐标中切换,这个就是制作技能痕迹的重要位置,新建的粒子系统一般都默认为local,所以在粒子本体移动的时候也跟着进行移动,改为world的 ...
- 透过摩拜和ofo,看产品从0到1时如何取舍需求(转)
大纲 背景介绍 从0至1,我们成功的关键是什么? 从0到1,我们为什么选择做?又为什么选择不做? 从0到1,我们面临什么选择?我们作出了什么选择? 从0到1,我们为什么作出了这种选择? 背景 在资本注 ...
- 有关PHP 10条有用的建议--转(柒捌玖零)
1.使用ip2long() 和long2ip()函数来把IP地址转化成整型存储到数据库里. 这种方法把存储空间降到了接近四分之一(char(15)的15个字节对整形的4个字节),计算一个特定的地址是不 ...
- 2018.11.07 bzoj1965: [Ahoi2005]SHUFFLE 洗牌(快速幂+exgcd)
传送门 发现自己的程序跑得好慢啊233. 管他的反正AC了 先手玩样例找了一波规律发现题目要求的就是a∗2m≡l(modn+1)a*2^m\equiv l \pmod {n+1}a∗2m≡l(modn ...
- 2018.11.01 NOIP训练 梭哈(模拟)
传送门 这题貌似不考智商啊. 直接按题意写就可以了. 事实上把牌从小到大排序之后写起来很舒服的. 然后就是有些地方可以人脑减代码量和判断次数. (提示:满堂红和某几种同类型的牌的大小判断) 然后注意A ...
- warning: this decimal constant is unsigned only in ISO C90问题的处理及理解
参考:https://blog.csdn.net/duguduchong/article/details/7709482 https://bbs.csdn.net/topics/391892978?p ...
- 牛客训练三:处女座和小姐姐(三)(数位dp)
题目链接:传送门 思路:数位dp的记忆化搜索模板 从高位向低位枚举,逐位确定每一位的6的个数,dp[i][s]表示处理到第i条边,状态为s时的数字的个数. 注意,要使用long long类型. #in ...
- SPRING 事务管理说明
spring 事务管理是通过AOP拦截指定的方法,进行事务管理. 事务配置 <aop:config proxy-target-class="true"> <aop ...