首先
w
1
w
2
w
3
⋯
w
n
n
\sqrt[n]{w_1w_2w_3\cdots w_n}
nw1w2w3⋯wn可以利用对数转化:
l
o
g
2
w
1
w
2
w
3
⋯
w
n
n
=
1
n
∑
l
o
g
2
w
i
log_2{\sqrt[n]{w_1w_2w_3\cdots w_n}}=\frac{1}{n}\sum log_2\ w_i
log2nw1w2w3⋯wn=n1∑log2 wi
那么令
t
i
=
l
o
g
2
w
i
t_i=log_2\ w_i
ti=log2 wi,问题就转化为了:
m
a
x
i
m
i
z
e
:
∑
t
i
∑
1
maximize:\frac{\sum{t_i}}{\sum{1}}
maximize:∑1∑ti
也就是一个分数规划:二分
λ
\lambda
λ,权值转化为
t
i
−
λ
t_i-\lambda
ti−λ。由于求最大值,那么:
如果最大的和小于
0
0
0,说明
λ
>
a
n
s
\lambda>ans
λ>ans,则
r
=
m
i
d
r=mid
r=mid。(减的多了)
如果最大的和大于
0
0
0,说明
λ
<
a
n
s
\lambda<ans
λ<ans,则
l
=
m
i
d
l=mid
l=mid。(减的少了)
在
A
C
AC
AC自动机上
D
P
DP
DP出最大值即可。
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示当前填到了原串的第
i
i
i位,处于自动机上的第
j
j
j位的和的最大值。
#include<bits/stdc++.h>
#define re register
#define cs const
cs int N=2010,maxS=2010;
cs double eps=1e-5;
int n,m;char S[N],spell[maxS];double W;
namespace AC{
cs int alpha=10;
int Pre[N][maxS],Ch[N][maxS],tot=0;double dp[N][maxS];
struct node{int son[alpha],fail,num;double val;}a[maxS];
inline void insert(char *s,double v){
int now=0,len=strlen(s);
for(int re i=0;i<len;++i){
if(!a[now].son[s[i]-'0'])
a[now].son[s[i]-'0']=++tot;
now=a[now].son[s[i]-'0'];
}a[now].val=v,a[now].num+=1;
}
inline void build_fail(){
std::queue<int> Q;
for(int re i=0,v;i<alpha;++i)
if(v=a[0].son[i]) Q.push(v),a[v].fail=0;
while(!Q.empty()){
int u=Q.front();Q.pop();
a[u].num+=a[a[u].fail].num;
a[u].val+=a[a[u].fail].val;
for(int re i=0,v;i<alpha;++i){
if(v=a[u].son[i]) a[v].fail=a[a[u].fail].son[i],Q.push(v);
else a[u].son[i]=a[a[u].fail].son[i];
}
}
}
inline bool check(double x){
memset(dp,-0x3f,sizeof dp);dp[0][0]=0;
for(int re i=0;i<n;++i){
for(int re j=0;j<=tot;++j)
if(S[i+1]=='.')
for(int re v=0,k=a[j].son[v];v<alpha;k=a[j].son[++v]){
double calc=dp[i][j]+a[k].val-x*a[k].num;
if(dp[i+1][k]<calc) dp[i+1][k]=calc,Pre[i+1][k]=j,Ch[i+1][k]=v;
}
else{
int k=a[j].son[S[i+1]-'0'];double calc=dp[i][j]+a[k].val-x*a[k].num;
if(dp[i+1][k]<calc) dp[i+1][k]=calc,Pre[i+1][k]=j;
}
}
for(int i=0;i<=tot;++i) if(dp[n][i]>0) return true;
return false;
}
inline void print(int l,int pos){
if(!l) return;print(l-1,Pre[l][pos]);
putchar((S[l]=='.')?(Ch[l][pos]+'0'):(S[l]));
}
inline void solve(){
double l=0.0,r=30;
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(dp[n][i]>0){print(n,i);return;}
}
}
using AC::insert;
int main(){
// freopen("4505.in","r",stdin);
scanf("%d%d%s",&n,&m,S+1);
while(m--) scanf("%s",spell),scanf("%lf",&W),W=log(W),insert(spell,W);
AC::build_fail();return AC::solve(),0;
}