我要是生在\(bj\)估计就凉了,一道\(d1t1\)做了\(4h+\)
首先看到这个鬼畜的计算贡献的柿子
\[\prod_{i=1}^na_i^{\frac{b_i}{\sum_{j=1}^nb_j}}\]
\(a_i\)为第\(i\)个字符串的价值,\(b_i\)为第\(i\)个字符串出现的次数
我们显然需要取一个\(\ln\)
就变成了
\[\sum_{i=1}^n\frac{b_i}{\sum_{j=1}^nb_j}\ln a_i\]
这样写太难看了
我们随便一些就变成了
\[\frac{\sum_{i=1}^nb_i\ln a_i}{\sum_{i=1}^nb_i}\]
一看这不分数规划吗,我们直接二分一个\(mid\)看看答案是否能更大就好了
如果更大
\[\frac{\sum_{i=1}^nb_i\ln a_i}{\sum_{i=1}^nb_i}>mid\]
也就是
\[\sum_{i=1}^nb_i(\ln a_i-mid)>0\]
显然这又是一个多串匹配的问题,我们直接上\(AC\)自动机
现在的问题就是在自动机上找到一条长度为\(n\)的路径,点权和最大
直接在自动机上按位\(dp\)就好了,\(dp[i][j]\)表示匹配的长度是\(i\)当前在自动机上的第\(j\)个节点的最大路径长度
代码
#include<queue> #include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define re register #define LL long long #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) const double eps=1e-12; const int maxn=1505; struct E{int v,nxt;}e[maxn]; int n,m,cnt,num,L; char S[maxn],T[maxn]; int id[maxn],fa[maxn],vis[2][maxn],son[maxn][10]; int r[maxn][maxn],c[maxn][maxn],head[maxn],tmp[maxn]; double val[maxn],d[maxn]; double dp[2][maxn],f[maxn][maxn]; inline void add(int x,int y) { e[++num].v=y;e[num].nxt=head[x];head[x]=num; } void Dfs(int x) { for(re int i=head[x];i;i=e[i].nxt) d[e[i].v]+=d[x],Dfs(e[i].v); } inline int pd(double a) {return a+eps>0&&a-eps<0;} inline void ins(int j) { int v; scanf("%s",T+1);scanf("%d",&v); int now=0,len=strlen(T+1);L+=len; for(re int i=1;i<=len;i++) { if(!son[now][T[i]-'0']) son[now][T[i]-'0']=++cnt; now=son[now][T[i]-'0']; } tmp[now]++;id[j]=now;val[j]=log(v); } inline void Build() { std::queue<int> q; for(re int i=0;i<=9;i++) if(son[0][i]) q.push(son[0][i]); while(!q.empty()) { int k=q.front();q.pop(); add(fa[k],k);tmp[k]+=tmp[fa[k]]; for(re int i=0;i<=9;i++) if(son[k][i]) fa[son[k][i]]=son[fa[k]][i],q.push(son[k][i]); else son[k][i]=son[fa[k]][i]; } } inline void Pre_work(double mid) { for(re int i=0;i<=cnt;i++) d[i]=0; for(re int i=1;i<=m;i++) d[id[i]]+=val[i]-mid; Dfs(0); } inline int check(double mid) { Pre_work(mid); memset(dp,-20,sizeof(dp)); dp[0][0]=0;int o=0;vis[0][0]=1; for(re int i=0;i<n;i++,o^=1) { memset(dp[o^1],-20,sizeof(dp[o^1])); memset(vis[o^1],0,sizeof(vis[o^1])); for(re int j=0;j<=cnt;j++) { if(!vis[o][j]) continue; if(S[i+1]>='0'&&S[i+1]<='9') { int v=son[j][S[i+1]-'0']; vis[o^1][v]=1; dp[o^1][v]=max(dp[o^1][v],dp[o][j]+d[v]); continue; } for(re int k=0;k<=9;k++) { int v=son[j][k]; vis[o^1][v]=1; dp[o^1][v]=max(dp[o^1][v],dp[o][j]+d[v]); } } } for(re int i=0;i<=cnt;i++) if(dp[o][i]>0&&!pd(dp[o][1])) return 1; return 0; } void dfs(int len,int now) { if(!len) return; dfs(len-1,c[len][now]); putchar(r[len][now]+'0'); } inline void solve(double mid) { Pre_work(mid); memset(f,-20,sizeof(f)); f[0][0]=0; for(re int i=0;i<n;i++) for(re int j=0;j<=cnt;j++) { if(S[i+1]>='0'&&S[i+1]<='9') { int v=son[j][S[i+1]-'0']; if(f[i][j]+d[v]>f[i+1][v]) { c[i+1][v]=j;r[i+1][v]=S[i+1]-'0'; f[i+1][v]=f[i][j]+d[v]; } continue; } for(re int k=0;k<=9;k++) { int v=son[j][k]; if(f[i][j]+d[v]>f[i+1][v]) { c[i+1][v]=j,r[i+1][v]=k; f[i+1][v]=f[i][j]+d[v]; } } } int t=0; for(re int i=1;i<=cnt;i++) if(f[n][i]>f[n][t]) t=i; dfs(n,t); } namespace sub1 { char g[15]; double ans=0; void dfs(int x) { if(x==n+1) { double w=0;int y=0,now=0; for(re int i=1;i<=n;i++) { now=son[now][S[i]-'0']; y+=tmp[now];w+=d[now]; } if(w/(1.0*y)>ans) { ans=w/(1.0*y); for(re int i=1;i<=n;i++) g[i]=S[i]; } return; } if(S[x]!='.') { dfs(x+1); return; } for(re int i=0;i<10;i++) { S[x]=i+48; dfs(x+1); } S[x]='.'; } inline void solve() { Pre_work(0); dfs(1); for(re int i=1;i<=n;i++) putchar(g[i]); } } int main() { scanf("%d%d",&n,&m); scanf("%s",S+1); for(re int i=1;i<=m;i++) ins(i); Build(); if(n<=6&&L<=20) { sub1::solve(); return 0; } double l=0,r=1e5+5,ans=0; while(r-l>eps) { double mid=(l+r)/2.0; if(check(mid)) l=mid,ans=mid; else r=mid; } solve(ans); return 0; }