題目讓咱們最大化\(val=\sqrt[k]{\prod_{i=1}^k w_i}\),其中\(k\)是咒語的個數,\(w_i\)是第\(i\)個咒語的神力
看着根號和累乘不爽,咱們兩邊同取\(\ln\)
\[\ln val=\frac{1}{k}\sum_{i=1}^k \ln w_i\]
易知當\(\ln val\)最大化時,\(val\)也最大化。因此咱們將問題轉化成了最大化\(\frac{1}{k}\sum_{i=1}^k \ln w_i\),咱們發現這是算數平均數。咱們珂以經過二分答案找到它的最大值,問題就是二分答案如何check是否合法:
當\(\frac{1}{k}\sum_{i=1}^k \ln w_i>mid\)時才合法
即當\(\sum_{i=1}^k(w_i-mid)>0\)時才合法
咱們先對全部咒語建AC自動機,在上面跑dp求出\(\sum_{i=1}^k(w_i-mid)\)的最大值,判斷是否可行
具體dp:就像其餘不少AC自動機上的dp同樣,設\(f[i][j]\)表示神杖前\(i\)個字符,匹配到了AC自動機上\(j\)號節點,依照套路轉移,就是不要忘了題目原有的限制
此算法精度偏差較大,但本題仍是珂以經過
#include <bits/stdc++.h>
#define db double
#define N 1505
#define eps 1e-6
using namespace std;
inline int read()
{
register int x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
int n,m;
char T[N],s[N],ans[N];
db V[N],val[N],f[N][N];
pair<int,int> pre[N][N];
struct node{
int son[10],fail,cnt;
db val;
}tr[N];
int tot=0;
inline void Insert(register char *s,register db v)
{
int len=strlen(s+1),now=0;
for(register int i=1;i<=len;++i)
{
if(!tr[now].son[s[i]-'0'])
tr[now].son[s[i]-'0']=++tot;
now=tr[now].son[s[i]-'0'];
}
++tr[now].cnt,tr[now].val+=v;
}
inline void getfail()
{
queue<int> q;
for(register int i=0;i<10;++i)
if(tr[0].son[i])
q.push(tr[0].son[i]);
while(!q.empty())
{
int u=q.front();
q.pop();
tr[u].cnt+=tr[tr[u].fail].cnt;
tr[u].val+=tr[tr[u].fail].val;
for(register int i=0;i<10;++i)
{
if(tr[u].son[i])
{
tr[tr[u].son[i]].fail=tr[tr[u].fail].son[i];
q.push(tr[u].son[i]);
}
else
tr[u].son[i]=tr[tr[u].fail].son[i];
}
}
}
inline void updateans(register int i,register int j)
{
if(!i)
return;
updateans(i-1,pre[i][j].first);
ans[i]=pre[i][j].second+'0';
}
inline bool check(register db mid)
{
memset(f,-0x3f,sizeof(f));
db inf=-f[0][0];
f[0][0]=0;
for(register int i=1;i<=n;++i)
for(register int j=0;j<=tot;++j)
{
if(fabs(f[i-1][j]+inf)<1)
continue;
if(T[i]=='.')
{
for(register int k=0;k<10;++k)
{
int v=tr[j].son[k];
if(f[i-1][j]+tr[v].val-tr[v].cnt*mid>f[i][v])
{
f[i][v]=f[i-1][j]+tr[v].val-tr[v].cnt*mid;
pre[i][v]=make_pair(j,k);
}
}
}
else
{
int k=T[i]-'0',v=tr[j].son[k];
if(f[i-1][j]+tr[v].val-tr[v].cnt*mid>f[i][v])
{
f[i][v]=f[i-1][j]+tr[v].val-tr[v].cnt*mid;
pre[i][v]=make_pair(j,k);
}
}
}
int pos=0;
for(register int i=1;i<=tot;++i)
if(f[n][i]>f[n][pos])
pos=i;
if(f[n][pos]>eps)
{
updateans(n,pos);
return 1;
}
else
return 0;
}
int main()
{
n=read(),m=read();
scanf("%s",T+1);
db L=0,R=0;
for(register int i=1;i<=m;++i)
{
scanf("%s",s+1);
V[i]=log(read());
R=max(R,V[i]);
Insert(s,V[i]);
}
getfail();
while(R-L>eps)
{
db mid=(L+R)/2.0;
if(check(mid))
L=mid;
else
R=mid;
}
for(register int i=1;i<=n;++i)
putchar(ans[i]);
return 0;
}