zoukankan      html  css  js  c++  java
  • [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
  • 相关阅读:
    linux-01-04(创建文件夹mkdir,进入目录命令cd,创建文件命令 echo cp vim touch等,批量创建文件操作)
    linux-05(tar命令的使用)
    linux-06(移动命令mv)
    linux-07(复制命令cp)
    linux-08(查看命令历史记录history)
    cookie
    vue-router路由懒加载
    setTimeout async promise执行顺序总结
    forEach陷阱
    函数节流与函数防抖之间的区别
  • 原文地址:https://www.cnblogs.com/hfctf0210/p/10747650.html
Copyright © 2011-2022 走看看