[BJOI2019]奥术神杖

https://www.luogu.com.cn/problem/P5319

把题目要求最大化的那个式子,取一手对数,然后就变成了一个分数规划问题。

二分后AC自动机上DP即可。

// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define N 2200
#define inf (1e9+7)
#define eps (1e-7)
#define db double
#define ll long long
#define ldb long double
using namespace std;
inline int read()
{
    char ch=0;
    int x=0,flag=1;
    while(!isdigit(ch)){ch=getchar();if(ch=='-')flag=-1;}
    while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch-'0');ch=getchar();}
    return x*flag;
}
queue<int>q;
char s[N],ch[N];
int root=1,size=1,f[N],nxt[N][10];
int insert()
{
    scanf("%s",s+1);
    int n=strlen(s+1),x=root;
    for(int i=1;i<=n;i++)
    {
        int k=s[i]-'0';
        if(!nxt[x][k])nxt[x][k]=++size;
        x=nxt[x][k];
    }
    return x;
}
void build()
{
    q.push(root);
    while(!q.empty())
    {
        int x=q.front();q.pop();
        for(int i=0;i<10;i++)
        if(nxt[x][i])
        {
            if(x!=root)f[nxt[x][i]]=nxt[f[x]][i];
            else f[nxt[x][i]]=root;
            q.push(nxt[x][i]);	
        }
        else
        {
            if(x!=root)nxt[x][i]=nxt[f[x]][i];
            else nxt[x][i]=root;
        }
    }
}
db w[N],dp[N][N];
int n,m,res,p[N],sz[N],pre[N][N];
struct edge{int to,nxt;}e[N*2];
int num,head[N];
inline void add(int x,int y)
{
    e[++num]={y,head[x]};head[x]=num;
    e[++num]={x,head[y]};head[y]=num;
}
void dfs(int x,int fa)
{
    w[x]+=w[fa];sz[x]+=sz[fa];
    for(int i=head[x];i!=-1;i=e[i].nxt)
    {
        int to=e[i].to;
        if(to==fa)continue;
        dfs(to,x);
    }
}
bool check(db mid)
{
    for(int i=0;i<=n;i++)
    for(int x=0;x<=size;x++)
    dp[i][x]=-inf,pre[i][x]=0;
    
    dp[0][root]=0;
    
    for(int i=0;i<n;i++)
    for(int x=1;x<=size;x++)
    if(dp[i][x]+inf>1)
    {
        if(ch[i+1]=='.')
        {
            for(int k=0;k<10;k++)
            {
                int to=nxt[x][k];
                if(dp[i+1][to]<dp[i][x]+(w[to]-sz[to]*mid))
                {
                    pre[i+1][to]=x;
                    dp[i+1][to]=dp[i][x]+(w[to]-sz[to]*mid);
                }
            }
        }
        else
        {
            int to=nxt[x][ch[i+1]-'0'];
            if(dp[i+1][to]<dp[i][x]+(w[to]-sz[to]*mid))
            {
                pre[i+1][to]=x;
                dp[i+1][to]=dp[i][x]+(w[to]-sz[to]*mid);
            }
        }
    }
    db ans=-inf;
    for(int x=1;x<=size;x++)if(dp[n][x]>ans)res=x,ans=dp[n][x];
    return (ans>0);
}
int main()
{
    n=read();m=read();scanf("%s",ch+1);
    for(int i=1;i<=m;i++)
    {
        int x=insert();
        sz[x]=1;w[x]=log(read());
    }
    build();
    num=-1;memset(head,-1,sizeof(head));
    for(int i=2;i<=size;i++)add(f[i],i);
    dfs(root,root);
    
    db l=0,r=30,mid;
    for(int i=1;i<=15;i++)
    {
        mid=(l+r)/2.0;
        if(check(mid))l=mid;else r=mid;
    }
    check(l);
    for(int i=n,x=res;i>=0;i--)p[i]=x,x=pre[i][x];
    for(int i=0;i<n;i++)
    {
        int x=p[i];
        if(ch[i+1]=='.')
        {
            for(int k=0;k<10;k++)
            if(nxt[x][k]==p[i+1]){printf("%d",k);break;}
        }
        else printf("%c",ch[i+1]);
    }
    return 0;
}
posted @ 2019-04-25 01:17  Creed-qwq  阅读(180)  评论(0编辑  收藏  举报