• 【LOJ】#2063. 「HAOI2016」字符合并


    题解

    dp[i][j][S]表示区间[i,j]内剩余的数位状压后为S的最大值

    这样转移起来不就是(n^3 2^8)了吗
    冷静一下,我们可以发现一段区间内剩下的数位的个数是一定的,也就是我们可以在枚举位数上减少一定复杂度
    我们转移的时候枚举一个末尾,也就是
    (dp[i][j][S] = dp[i][k][S >> 1] + dp[k + 1][j][S & 1])
    我们还需要保证[k + 1,j]的长度-1后是(K - 1)的倍数

    这样的话最后跑得还是很快的

    代码

    #include <bits/stdc++.h>
    #define enter putchar('
    ')
    #define space putchar(' ')
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define MAXN 100005
    #define pb push_back
    //#define ivorysi
    using namespace std;
    typedef long long int64;
    typedef double db;
    template<class T>
    void read(T &res) {
        res = 0;T f = 1;char c = getchar();
        while(c < '0' || c > '9') {
            if(c == '-') f = -1;
            c = getchar();
        }
        while(c >= '0' && c <= '9') {
            res = res * 10 + c - '0';
            c = getchar();
        }
        res *= f;
    }
    template<class T>
    void out(T x) {
        if(x < 0) {x = -x;putchar('-');}
        if(x >= 10) out(x / 10);
        putchar('0' + x % 10);
    }
    int N,K;
    int64 dp[305][305][(1 << 8) + 5],val[(1 << 8) + 5],ch[(1 << 8) + 5];
    char s[305];
    void update(int64 &x,int64 y) {
        x = max(x,y);
    }
    void Solve() {
        read(N);read(K);
        scanf("%s",s + 1);
        for(int i = 0 ; i < (1 << K) ; ++i) {read(ch[i]);read(val[i]);}
        memset(dp,-1,sizeof(dp));
        for(int i = 1 ; i <= N ; ++i) dp[i][i][s[i] - '0'] = 0;
        for(int d = 2 ; d <= N ; ++d) {
            for(int i = 1 ; i <= N ; ++i) {
                int j = i + d - 1;
                if(j > N) break;
                int t = (d - 1) % (K - 1) + 1;
                if(t == 1) t = K;
                for(int S = 0 ; S < (1 << t) ; ++S) {
                    for(int h = 0 ; h <= N ; ++h) {
                        int l = h * (K - 1) + 1;
                        if(l > d) break;
                        if(dp[i][j - l][S >> 1] == -1 || dp[j - l + 1][j][S & 1] == -1) continue;
                        if(t == K) update(dp[i][j][ch[S]],dp[i][j - l][S >> 1] + dp[j - l + 1][j][S & 1] + val[S]);
                        else update(dp[i][j][S],dp[i][j - l][S >> 1] + dp[j - l + 1][j][S & 1]);
                    }
                }
            }
        }
        int64 res = 0;
        for(int S = 0 ; S < (1 << K) ; ++S) {
            res = max(res,dp[1][N][S]);
        }
        out(res);enter;
    }
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        Solve();
        return 0;
    }
    
  • 相关阅读:
    DLL注入之Appinit_Dlls
    VC下遍历文件夹中的所有文件的几种方法
    Windows下C语言的Socket编程例子(TCP和UDP)
    Windows进程间共享内存通信实例
    window下线程同步之(Mutex(互斥器) )
    如何安装win10和linux [ubuntu14]双系统
    Windows虚拟地址转物理地址(原理+源码实现,附简单小工具)
    Windows驱动中通过MDL实现用户态与核心态共享内存
    C# Label显示多行文本及换行(WinForm/WebForm)
    使用delegate实现简单的查询功能
  • 原文地址:https://www.cnblogs.com/ivorysi/p/9512497.html
Copyright © 2020-2023  润新知