zoukankan      html  css  js  c++  java
  • scut 125. 笔芯回文

    https://scut.online/p/125

    看数据量,这题可能是O(n^2)的dp

    也可能是区间dp,但是区间dp一般复杂度是O(n^3),虽然也可以优化,但是比赛的时候那么多人“秒”了,应该不会是那么麻烦的。

    套路:设dp[i]表示前i个字符中能拿到的最大贡献。dp[len]就是答案。

    如果[L, R]这段区间能组成回文串,那么就有两种决策,删除或则不删除。

    删除:dp[R] = dp[L - 1] + a[R - L + 1]

    不:  dp[R] = dp[R];

    取个max就行。

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <assert.h>
    #define IOS ios::sync_with_stdio(false)
    using namespace std;
    #define inf (0x3f3f3f3f)
    typedef long long int LL;
    
    
    #include <iostream>
    #include <sstream>
    #include <vector>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    #include <bitset>
    const int maxn = 1e5 + 20;
    int a[maxn];
    LL dp[maxn];
    char str[maxn], sub[maxn];
    int p[maxn];
    int manacher(char str[], int lenstr) {
        str[0] = '*'; //表示一个不可能的值
        //目标要插入lenstr+1个'#',所以长度变成2*lenstr+1
        for (int i = lenstr; i >= 0; i--) { //str[lenstr+1]是''
            //i=lenstr时,i+i+2那个值要赋为'';
            //总长度只能是lenstr+lenstr+2,所以i从lenstr开始枚举
            str[i + i + 2] = str[i + 1];
            str[i + i + 1] = '#';
        }
        int id = 0, maxlen = 0; //现在开始在str[2]了
        for (int i = 2; i <= 2 * lenstr + 1; i++) { //2*lenstr+1是'#'没用
            if (p[id] + id > i) { //没取等号的,只能去到p[id]+id-1
                //p[id]+id是越界的,减去i即为区间长度
                //p[id]+id-i,这个是所有可能中的最大值了
                p[i] = min(p[id] + id - i, p[2 * id - i]);
            } else p[i] = 1; //记得修改的是p[i]
            while (str[i + p[i]] == str[i - p[i]]) ++p[i];
            if (p[id] + id < p[i] + i) id = i;
            maxlen = max(maxlen, p[i]);
        }
        return maxlen - 1;
    }
    bool isok(int be, int en) {
        int len = en - be + 1;
        be <<= 1;
        en <<= 1;
        int mid = (be + en) >> 1;
        return p[mid] - 1 >= len;
    }
    void work() {
        int n;
        cin >> n;
        for (int i = 1; i <= n; ++i) cin >> a[i];
        memset(dp, 0, sizeof dp);
        cin >> str + 1;
        int lenstr = strlen(str + 1);
        strcpy(sub + 1, str + 1);
        manacher(str, lenstr);
        for (int i = 1; i <= lenstr; ++i) {
            for (int j = 1; j <= i; ++j) {
                if (i - j + 1 > n) continue;
                if (isok(j, i)) {
                    dp[i] = max(dp[i], dp[j - 1] + a[i - j + 1]);
                }
            }
        }
        cout << dp[lenstr] << endl;
    }
    
    int main() {
    #ifdef local
        freopen("data.txt", "r", stdin);
    //    freopen("data.txt", "w", stdout);
    #endif
        int t;
        cin >> t;
        while (t--) work();
        return 0;
    }
    View Code
  • 相关阅读:
    Deepin Linux下安装安卓应用的各种方式
    win下的终端使用指南
    IDEA自定义TODO
    WSL的ssh-agent问题
    MySQL数据类型
    MySQL常用命令.md
    Period 时间坑
    exp/imp管理
    expdp和impdp管理(逻辑导入导出)
    同义词
  • 原文地址:https://www.cnblogs.com/liuweimingcprogram/p/6786544.html
Copyright © 2011-2022 走看看