zoukankan      html  css  js  c++  java
  • [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;
    }
    
  • 相关阅读:
    Python——6切片
    Python——5函数
    Python——4Dict和Set类型
    C# for循环
    C# while循环
    C#循环结构
    C#判断
    C#运算符
    windows安装IIS不成功的原因
    “未在本地计算机上注册“Microsoft.Jet.OLEDB.4.0”提供程序
  • 原文地址:https://www.cnblogs.com/Creed-qwq/p/10766006.html
Copyright © 2011-2022 走看看