zoukankan      html  css  js  c++  java
  • luoguP5319 [BJOI2019]奥术神杖 AC自动机+01分数规划+dp

    显然取对数,然后二分答案进行 01 分数规划.

    设 $f[i][j]$ 表示在 AC 自动机上的点 $i$ ,匹配到了 $j$ 位的最大价值.

    转移的时候判断一下当前是点还是数字,然后在 AC 自动机上的终止节点上算一下贡献就行.   

    构建 AC 自动机的时候要注意:点 $i$ 的价值是 val[i]+i祖先的贡献和.   

    然后 01 分数规划的时候要注意精度,且要判断 f[n][i] 是否大于 0,不能直接判 f[j][i].   

    code:  

    #include <bits/stdc++.h>   
    #define N 1608   
    #define inf 100000   
    #define ll long long 
    #define setIO(s) freopen(s".in","r",stdin) 
    using namespace std;
    const double eps=1e-7;     
    struct data 
    {
        int ch[10],f,fl,sum;       
        double det;   
    }s[N];     
    queue<int>q;    
    double f[N][N];  
    char str[N],ar[N];       
    int tot,n,m,loc[N],pre[N][N],col[N][N];                 
    void ins(int d) 
    {
        int x=0,y,z,c; 
        scanf("%s%d",ar+1,&z),y=strlen(ar+1);   
        for(int i=1;i<=y;++i) 
        {
            c=ar[i]-'0';    
            if(!s[x].ch[c]) s[x].ch[c]=++tot;  
            x=s[x].ch[c];   
        }   
        s[x].fl=1,s[x].det+=log(z),loc[d]=x,s[x].sum++;       
    }
    void build() 
    { 
        for(int i=0;i<10;++i)  if(s[0].ch[i]) q.push(s[0].ch[i]);   
        while(!q.empty()) 
        {
            int u=q.front(); q.pop();   
            for(int i=0;i<10;++i) 
            {
                if(!s[u].ch[i]) { s[u].ch[i]=s[s[u].f].ch[i]; continue; }   
                int v=s[u].ch[i]; 
                s[v].f=s[s[u].f].ch[i];    
                s[v].sum+=s[s[v].f].sum;  
                s[v].det+=s[s[v].f].det;   
                q.push(v);   
            }
        }
    }
    int check(double t) 
    {   
        int x,y,z=0,c;
        for(int i=1;i<=tot;++i)  s[i].det-=s[i].sum*t;              
        for(int i=0;i<=n;++i) for(int j=0;j<=tot;++j) f[i][j]=-inf;   
        f[0][0]=0;               
        for(int i=0;i<n;++i) 
        {    
            for(int j=0;j<=tot;++j) 
            {    
                if(str[i+1]=='.') 
                {   
                    for(c=0;c<10;++c)       
                    {
                        if(f[i][j]+s[s[j].ch[c]].det>f[i+1][s[j].ch[c]]) 
                        { 
                            f[i+1][s[j].ch[c]]=f[i][j]+s[s[j].ch[c]].det;         
                            pre[i+1][s[j].ch[c]]=j;   
                            col[i+1][s[j].ch[c]]=c;    
                        }
                    }
                } 
                else 
                { 
                    c=str[i+1]-'0';       
                    if(f[i][j]+s[s[j].ch[c]].det>f[i+1][s[j].ch[c]]) 
                    { 
                        f[i+1][s[j].ch[c]]=f[i][j]+s[s[j].ch[c]].det;       
                        pre[i+1][s[j].ch[c]]=j;   
                        col[i+1][s[j].ch[c]]=c;    
                    }
                }
            }
        }
        for(int i=0;i<=tot;++i)  if(f[n][i]>0) z=1;  
        for(int i=1;i<=tot;++i)  s[i].det+=s[i].sum*t;              
        return z;    
    }   
    void print(int x,int l) 
    {
        if(l>1) print(pre[l][x],l-1);   
        printf("%d",col[l][x]);   
    }
    int main() 
    { 
        // setIO("input");   
        scanf("%d%d%s",&n,&m,str+1);      
        for(int i=1;i<=m;++i) ins(i);  
        build();  
        // 注意这里 01 分数规划的写法  !!   
        double l=0.0,r=log(1e9+9),mid,ans;   
        while(r-l>=eps) 
        {   
            mid=(l+r)*0.5;        
            if(check(mid)) l=mid;    
            else r=mid;   
        }                    
        check(l);      
        for(int i=0;i<=tot;++i)    if(f[n][i]>0) { print(i,n); break;  }   
        return 0;   
    }
    

      

  • 相关阅读:
    allocator类
    智能指针shared_ptr
    字面值常量类
    转换构造函数
    委托构造函数
    访问说明符&封装
    const成员函数
    函数指针
    constexper和常量表达式
    函数返回数组指针
  • 原文地址:https://www.cnblogs.com/guangheli/p/13069812.html
Copyright © 2011-2022 走看看