• P5319 [BJOI2019]奥术神杖


    gate

    用时:正常的时间大概120min
    这题spj...我能说我对着不存在的bug找了半天吗...我是傻逼(1/1)

    因为要求神力值最大的字符串,不用求这个数值,
    可以把每个值取(log)
    把几何平均数转化为算数平均数。

    (sqrt[n]{prod a_i}=frac{1}{n}sum log a_i)

    多模式串匹配( ightarrow AC)自动机
    求平均值( ightarrow 0/1)分数规划

    设当前二分到的答案为(mid)
    (frac{1}{n} sum limits_{i=1} ^{n} log a_i ge mid)
    (sum limits_{i=1} ^{n} log a_i ge n imes mid)
    (sum limits_{i=1} ^{n} log (a_i-mid) ge 0)

    (AC)自动机上(DP)
    设:
    (f[i][j])表示当前匹配到第(i)个字符,且第(i)个字符在(trie)树上的编号为(j)
    (f[i][trie[j].son[x]] = max(f[i-1][j] + val[trie[j].son[x]]))

    其中,
    (x in [0,9]),若(x)在原串上已确定则不用枚举(x)
    (val[i] = log (a_i- cnt_i imes mid))
    每次转移时,记录这个状态是从哪个字符及(trie)树上的编号转移过来的。

    注意,建立(AC)自动机时,每个节点都要继承(fail)的所有祖先的信息,即

    trie[u].cnt += trie[trie[u].fail].cnt;
    trie[u].sum += trie[trie[u].fail].sum;
    

    最后判断是否(max(f[n][x]) > 0)
    如果是,则记录当前字符串。

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<cstring>
    #include<queue>
    #define Mogeko qwq
    using namespace std;
    
    const int maxn = 1505;
    const int INF = 0x3f3f3f3f;
    const double eps = 1e-6;
    
    int n,m,now,num;
    double l,r,mid;
    char t[maxn],s[maxn],T[maxn];
    double val[maxn],f[maxn][maxn],w[maxn];
    pair<int,int> pre[maxn][maxn];
    
    struct Trie{
        int son[10],fail;
        double cnt,sum;
    }trie[maxn];
    
    void insert(char s[],int x){
        int len = strlen(s);
        int u = 0;
        for(int i = 0;i < len;i++){
            int v = s[i]-'0';
            if(!trie[u].son[v]) trie[u].son[v] = ++num;
            u = trie[u].son[v];
        }
        trie[u].cnt++;
        trie[u].sum += w[x];
    }
    
    void getf(){
        queue <int> q;
        for(int i = 0;i < 10;i++)
            if(trie[0].son[i]){
                trie[trie[0].son[i]].fail = 0;
                q.push(trie[0].son[i]);
            }
        while(!q.empty()){
            int u = q.front();
            q.pop();
            trie[u].cnt += trie[trie[u].fail].cnt;
            trie[u].sum += trie[trie[u].fail].sum;
            for(int i = 0;i < 10;i++){
                if(trie[u].son[i]){
                    trie[trie[u].son[i]].fail = trie[trie[u].fail].son[i];
                    q.push(trie[u].son[i]);
                }
                else
                    trie[u].son[i] = trie[trie[u].fail].son[i];
            }    
        }
    }
    
    bool check(){
        memset(f,-INF,sizeof f);
        f[0][0] = 0;
        for(int i = 0;i <= num;i++)    
            val[i] = trie[i].sum - trie[i].cnt * mid;
        for(int i = 1;i <= n;i++)
            for(int j = 0;j <= num;j++){
                if(f[i-1][j] == -INF) continue;
                if(t[i] == '.')
                    for(int k = 0;k < 10;k++){
                        int v = trie[j].son[k];
                        if(f[i][v] < f[i-1][j] + val[v]){
                            f[i][v] = f[i-1][j] + val[v];
                            pre[i][v] = make_pair(k,j);
                        }
                    }
                else{
                    int k = t[i]-'0';
                    int v = trie[j].son[k];
                    if(f[i][v] < f[i-1][j] + val[v]){
                        f[i][v] = f[i-1][j] + val[v];
                        pre[i][v] = make_pair(k,j);
                    }
                }
            }
        now = 0;
        for(int i = 0;i <= num;i++)
            if(f[n][i] > f[n][now]) now = i;
        return (f[n][now] > 0);
    }
    
    void update(){
        for(int i = n;i >= 1;i--){
            T[i] = pre[i][now].first;
            now = pre[i][now].second;
        }
    }
    
    int main(){
        scanf("%d%d",&n,&m);
        scanf("%s",t+1);
        for(int i = 1;i <= m;i++){
            scanf("%s%lf",s,&w[i]);
            w[i] = log(w[i]);
            insert(s,i);
        }
        getf();
        l = 0, r = log(INF);
        while(r-l > eps){
            mid = (l+r)*0.5;
            if(check()) {
                l = mid;
                update();
            }
            else r = mid;        
        }
        for(int i = 1; i <= n;i++)
            printf("%c",T[i]+'0');
        printf("
    ");
        return 0;
    }
    
  • 相关阅读:
    微信小程序统一管理接口
    微信小程序购物车
    微信小程序表单的取值
    在VS Code中编写IAR项目
    【管理员已阻止你运行此应用】windows defender图标打叉,无法打开mmc.exe解决办法
    Eclipse普通java Project文件路径问题
    【线性表基础】基于线性表的简单算法【Java版】
    【线性表基础】顺序表和单链表的插入、删除等基本操作【Java版】
    Java逆序输出整数
    Java打印实心、空心的三角形和菱形
  • 原文地址:https://www.cnblogs.com/mogeko/p/13186247.html
Copyright © 2020-2023  润新知