Palindrome Bo (预处理 + 区间DP)

先进行离散化,然后再预处理出所有位置的下一个元素,做好这一步对时间的优化非常重要。

剩下的就是一般的DP了。区间DP

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 5005;
const ll mod = 1e9 + 7;

ll dp[maxn][maxn], f[maxn][maxn], a[maxn];
int nex[maxn][maxn], pre[maxn][maxn];
pair<ll, int>discre[maxn];

int main(){
    int n;while(~scanf("%d", &n)){
        for(int i = 1; i <= n; i ++){
            scanf("%lld", &a[i]);
            discre[i].first = a[i];
            discre[i].second = i;
        } sort(discre + 1, discre + 1 + n);
        discre[0].first = -1;
        int cnt = 0;
        for(int i = 1; i <= n; i ++){
            if(discre[i].first != discre[i - 1].first) cnt ++;
            a[discre[i].second] = cnt;
        }
        a[0] = a[n + 1] = cnt + 1;
        memset(dp, -1, sizeof(dp));
        memset(nex, 0, sizeof(nex));
        memset(pre, 0, sizeof(pre));
        for(int i = 0; i <= n + 1; i ++){
            for(int j = i + 1; j <= n + 1; j ++)
                if(!nex[i][a[j]]) nex[i][a[j]] = j;
            for(int j = i - 1; j >= 0; j --)
                if(!pre[i][a[j]]) pre[i][a[j]] = j;
        }
        for(int l = n + 1; l >= 0; l -- ){
            ll ans1 = 0, ans2 = 1;
            for(int r = l; r <= n + 1; r ++){
                ll tmp1, tmp2;
                if(l == r){
                    dp[l][r] = f[l][r] = 1;
                    continue;
                }

                if(a[r - 1] <= a[l]){
                    tmp1 = dp[nex[l][a[r-1]]][pre[r-1][a[r-1]]];
                    tmp2 =  f[nex[l][a[r-1]]][pre[r-1][a[r-1]]];
                    if(ans1 == tmp1) ans2 = (ans2 - tmp2 + mod) % mod;
                    if(ans1 < tmp1) ans1 = tmp1, ans2 = tmp2;
                    tmp1 = dp[nex[l][a[r-1]]][r - 1];
                    tmp2 =  f[nex[l][a[r-1]]][r - 1];
                    if(ans1 == tmp1) ans2 = (ans2 + tmp2) % mod;
                    if(ans1 < tmp1) ans1 = tmp1, ans2 = tmp2;
                }

                if(a[l] == a[r]){
                    dp[l][r] = ans1 + 2;
                    f[l][r] = ans2;
                }else dp[l][r] = f[l][r] = 0;
            }
        }
        ll ans1 = 0, ans2 = 0;
        for(int i = 1; i <= cnt; i ++){
            if(dp[nex[0][i]][pre[n+1][i]] > ans1){
                ans1 = dp[nex[0][i]][pre[n+1][i]];
                ans2 =  f[nex[0][i]][pre[n+1][i]];
            }else if(ans1 == dp[nex[0][i]][pre[n+1][i]])
                ans2 = (ans2 + f[nex[0][i]][pre[n+1][i]]) % mod;
        }
        printf("%lld %lld
",ans1, ans2);
    }
    return 0;
}
more crazy more get!
原文地址:https://www.cnblogs.com/wethura/p/9820368.html