zoukankan      html  css  js  c++  java
  • [BJOI2019]奥术神杖

    题目

    我要是生在(bj)估计就凉了,一道(d1t1)做了(4h+)

    首先看到这个鬼畜的计算贡献的柿子

    [prod_{i=1}^na_i^{frac{b_i}{sum_{j=1}^nb_j}} ]

    (a_i)为第(i)个字符串的价值,(b_i)为第(i)个字符串出现的次数

    我们显然需要取一个(ln)

    就变成了

    [sum_{i=1}^nfrac{b_i}{sum_{j=1}^nb_j}ln a_i ]

    这样写太难看了

    我们随便一些就变成了

    [frac{sum_{i=1}^nb_iln a_i}{sum_{i=1}^nb_i} ]

    一看这不分数规划吗,我们直接二分一个(mid)看看答案是否能更大就好了

    如果更大

    [frac{sum_{i=1}^nb_iln a_i}{sum_{i=1}^nb_i}>mid ]

    也就是

    [sum_{i=1}^nb_i(ln a_i-mid)>0 ]

    显然这又是一个多串匹配的问题,我们直接上(AC)自动机

    现在的问题就是在自动机上找到一条长度为(n)的路径,点权和最大

    直接在自动机上按位(dp)就好了,(dp[i][j])表示匹配的长度是(i)当前在自动机上的第(j)个节点的最大路径长度

    代码

    #include<queue>
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define re register
    #define LL long long
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    const double eps=1e-12;
    const int maxn=1505;
    struct E{int v,nxt;}e[maxn];
    int n,m,cnt,num,L;
    char S[maxn],T[maxn];
    int id[maxn],fa[maxn],vis[2][maxn],son[maxn][10];
    int r[maxn][maxn],c[maxn][maxn],head[maxn],tmp[maxn];
    double val[maxn],d[maxn];
    double dp[2][maxn],f[maxn][maxn];
    inline void add(int x,int y) {
        e[++num].v=y;e[num].nxt=head[x];head[x]=num;
    }
    void Dfs(int x) {
        for(re int i=head[x];i;i=e[i].nxt)
            d[e[i].v]+=d[x],Dfs(e[i].v);
    }
    inline int pd(double a) {return a+eps>0&&a-eps<0;}
    inline void ins(int j) {
        int v;
        scanf("%s",T+1);scanf("%d",&v);
        int now=0,len=strlen(T+1);L+=len;
        for(re int i=1;i<=len;i++) {
            if(!son[now][T[i]-'0']) son[now][T[i]-'0']=++cnt;
            now=son[now][T[i]-'0'];
        }
        tmp[now]++;id[j]=now;val[j]=log(v);
    }
    inline void Build() {
        std::queue<int> q;
        for(re int i=0;i<=9;i++) if(son[0][i]) q.push(son[0][i]);
        while(!q.empty()) {
            int k=q.front();q.pop();
            add(fa[k],k);tmp[k]+=tmp[fa[k]];
            for(re int i=0;i<=9;i++)
            if(son[k][i]) fa[son[k][i]]=son[fa[k]][i],q.push(son[k][i]);
                else son[k][i]=son[fa[k]][i];
        }
    }
    inline void Pre_work(double mid) {
        for(re int i=0;i<=cnt;i++) d[i]=0;
        for(re int i=1;i<=m;i++) d[id[i]]+=val[i]-mid;
        Dfs(0);
    }
    inline int check(double mid) {
        Pre_work(mid);
        memset(dp,-20,sizeof(dp));
        dp[0][0]=0;int o=0;vis[0][0]=1;
        for(re int i=0;i<n;i++,o^=1)  {
            memset(dp[o^1],-20,sizeof(dp[o^1]));
            memset(vis[o^1],0,sizeof(vis[o^1]));
            for(re int j=0;j<=cnt;j++) {
                if(!vis[o][j]) continue;
                if(S[i+1]>='0'&&S[i+1]<='9') {
                    int v=son[j][S[i+1]-'0'];
                    vis[o^1][v]=1;
                    dp[o^1][v]=max(dp[o^1][v],dp[o][j]+d[v]);
                    continue;
                }
                for(re int k=0;k<=9;k++) {
                    int v=son[j][k];
                    vis[o^1][v]=1;
                    dp[o^1][v]=max(dp[o^1][v],dp[o][j]+d[v]);
                }
            }
        }
        for(re int i=0;i<=cnt;i++) 
        if(dp[o][i]>0&&!pd(dp[o][1])) 
            return 1;
        return 0;
    }
    void dfs(int len,int now) {
        if(!len) return;
        dfs(len-1,c[len][now]);
        putchar(r[len][now]+'0');
    }
    inline void solve(double mid) {
        Pre_work(mid);
        memset(f,-20,sizeof(f));
        f[0][0]=0;
        for(re int i=0;i<n;i++) 
            for(re int j=0;j<=cnt;j++) {
                if(S[i+1]>='0'&&S[i+1]<='9') {
                    int v=son[j][S[i+1]-'0'];
                    if(f[i][j]+d[v]>f[i+1][v]) {
                        c[i+1][v]=j;r[i+1][v]=S[i+1]-'0';
                        f[i+1][v]=f[i][j]+d[v];
                    }
                    continue;
                }
                for(re int k=0;k<=9;k++) {
                    int v=son[j][k];
                    if(f[i][j]+d[v]>f[i+1][v]) {
                        c[i+1][v]=j,r[i+1][v]=k;
                        f[i+1][v]=f[i][j]+d[v];
                    }
                }
            }
        int t=0;
        for(re int i=1;i<=cnt;i++)
        if(f[n][i]>f[n][t]) t=i;
        dfs(n,t);
    }
    namespace sub1 {
        char g[15];
        double ans=0;
        void dfs(int x) {
            if(x==n+1) {
                double w=0;int y=0,now=0;
                for(re int i=1;i<=n;i++) {
                    now=son[now][S[i]-'0'];
                    y+=tmp[now];w+=d[now];
                }
                if(w/(1.0*y)>ans) {
                    ans=w/(1.0*y);
                    for(re int i=1;i<=n;i++) g[i]=S[i];
                }
                return;
            } 
            if(S[x]!='.') {
                dfs(x+1);
                return;
            }
            for(re int i=0;i<10;i++) {
                S[x]=i+48;
                dfs(x+1);
            }
            S[x]='.';
            
        }
        inline void solve() {
            Pre_work(0);
            dfs(1);
            for(re int i=1;i<=n;i++) putchar(g[i]);
        }
    }
    int main() {
        scanf("%d%d",&n,&m);
        scanf("%s",S+1);
        for(re int i=1;i<=m;i++) ins(i);
        Build();
        if(n<=6&&L<=20) {
            sub1::solve();
            return 0;
        }
        double l=0,r=1e5+5,ans=0;
        while(r-l>eps) {
            double mid=(l+r)/2.0;
            if(check(mid)) l=mid,ans=mid;
                else r=mid;
        }
        solve(ans);
        return 0;
    }
    
    
    
    
  • 相关阅读:
    轻轻松松教你写日志-超级简单
    JAVA实现KNN分类
    怎样给filter加入自己定义接口
    设计模式之Visitor模式(笔记)
    Leet Code OJ 237. Delete Node in a Linked List [Difficulty: Easy]
    在C#中怎样推断线程当前所处的状态
    leetCode 83.Remove Duplicates from Sorted List(删除排序链表的反复) 解题思路和方法
    谈谈源码管理那点事儿(一)——源码管理十诫(转)
    安装gi的时候回退root.sh的运行
    Android开发学习之路--异步消息Handler,Message,Looper和AsyncTask之初体验
  • 原文地址:https://www.cnblogs.com/asuldb/p/10748113.html
Copyright © 2011-2022 走看看