• [BJOI2019]奥术神杖(分数规划+AC自动机+DP)


    题解:很显然可以对权值取对数,然后把几何平均值转为算术平均值,然后很显然是分数规划。先对每个模式串建立AC自动机,每个节点w[i],sz[i]分别表示以其为前缀的字符串,然后再二分最优解k,然后w[i]-=k*sz[i],然后枚举T,在AC自动机上DP一遍,求最大值是否大于0即可。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1555;
    int n,m,tot,ch[N][10],fail[N],sz[N],g[N][N],h[N][N];
    double w[N],f[N][N];
    char T[N],str[N],ans[N];
    void insert(int v)
    {
        int u=0,len=strlen(str+1);
        for(int i=1;i<=len;++i)
        {
            if(!ch[u][str[i]-'0'])ch[u][str[i]-'0']=++tot;
            u=ch[u][str[i]-'0'];
        }
        w[u]=log(v),sz[u]+=1;
    }
    void build()
    {
        queue<int>q;
        for(int i=0;i<10;i++)if(ch[0][i])q.push(ch[0][i]);
        while(!q.empty())
        {
            int u=q.front();q.pop();
            w[u]+=w[fail[u]],sz[u]+=sz[fail[u]];
            for(int i=0;i<10;i++)
            if(ch[u][i])fail[ch[u][i]]=ch[fail[u]][i],q.push(ch[u][i]);
            else ch[u][i]=ch[fail[u]][i];
        }
    }
    void dp(int i,int j,int k)
    {
        int c=ch[j][k];
        if(f[i][c]<f[i-1][j]+w[c])f[i][c]=f[i-1][j]+w[c],g[i][c]=j,h[i][c]=k;
    }
    bool check(double val)
    {
        for(int i=0;i<=tot;i++)w[i]-=val*sz[i];
        for(int i=0;i<=n;i++)
        for(int j=0;j<=tot;j++)
        f[i][j]=-1e300;
        f[0][0]=0;
        for(int i=1;i<=n;i++)
        for(int j=0;j<=tot;j++)
        if(T[i]=='.')for(int k=0;k<10;k++)dp(i,j,k);
        else dp(i,j,T[i]-'0');
        double ans=-1e300;
        for(int i=1;i<=tot;i++)ans=max(ans,f[n][i]);
        for(int i=0;i<=tot;i++)w[i]+=val*sz[i];
        return ans>0;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        scanf("%s",T+1);
        for(int i=1,x;i<=m;i++)scanf("%s%d",str+1,&x),insert(x);
        build();
        double l=0,r=25,mid;
        while(r-l>1e-3)
        {
            mid=(l+r)/2;
            if(check(mid))l=mid;else r=mid;
        }
        check(l);
        int pos=0;
        for(int i=1;i<=tot;i++)if(f[n][i]>f[n][pos])pos=i;
        for(int i=n;i;i--)ans[i]=h[i][pos]+48,pos=g[i][pos];
        for(int i=1;i<=n;i++)putchar(ans[i]);
    }
    View Code
  • 相关阅读:
    【Javascript】JS单例模式的简单实现
    【Javascript】Javascript中如何判断变量是数组类型
    买卖股票的最佳时机 II
    只出现一次的数字
    删除排序数组中的重复项
    两数之和
    Android系统中Fastboot和Recovery所扮演的角色。
    虚函数、纯虚函数、抽象类、接口 (Java_C++_C#)
    关于cmd中执行命令路径包含空格的解决办法
    Windows API 编程学习记录<三>
  • 原文地址:https://www.cnblogs.com/hfctf0210/p/10747650.html
Copyright © 2020-2023  润新知