2016多校联合第三场 HDU5760

给你个 n ,然后 n 个数,你要找到一个最长的序列 s ,输出其长度,并且输出不同的 s 的个数。 s 序列必须是回文的,并且中间最小,往两边依次增大,可以相等。 s1 s2 不同当且仅当长度不同或者存在某位 s1[i]!=s2[i]

这个dp比较难。

n范围比较小,先把 a 数组离散化。方便之后处理。再预处理两个数组 pre[i][j] nxt[i][j] 分别表示以 i 起左边第一个等于j的数的位置和以 i 起右边第一个等于j的数的位置。

dp[l][r] 元组表示 a[l]==a[r] 的时候的最长s串和最长串个数。那么有 dp[l][r]=max{dp[nxt[l][c]][pre[r][c]]+2} 枚举c再枚举区间的复杂度是 n3 显然超时。

如果固定 l ,逐渐向右扫的时候, dp 值肯定是越来越优的。我们设一个临时变量 ans 来表示 l 右边开始某位置的最优值,然后往右扫的同时就可以直接用此临时变量更新我们的 dp[l][r] ,当然,也需要把 ans 的值也更新。当遇到相同值的时候,要加上数量,然后就是去重

每次更新 ans 的时候,如果发现当前串的长度等于 ans 那么需要把个数加进 ans 但是如果之前加过一样的长度,并且二者首尾一样,那么说明后者包含了更多的 res (因为范围更大)那么减去原来的,加上后来的,刚好不重不漏。

//
//  Created by Running Photon
//  Copyright (c) 2015 Running Photon. All rights reserved.
//
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define ALL(x) x.begin(), x.end()
#define INS(x) inserter(x, x,begin())
#define ll long long
#define CLR(x) memset(x, 0, sizeof x)
using namespace std;
const int inf = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const int maxn = 1e6 + 10;
const int maxv = 5e3 + 10;
const double eps = 1e-9;

int a[maxv];
int pre[maxv][maxv], nxt[maxv][maxv];
typedef pair <int, int> sta;
sta dp[maxv][maxv];
int main() {
#ifdef LOCAL
    freopen("C:\\Users\\Administrator\\Desktop\\in.txt", "r", stdin);
    freopen("C:\\Users\\Administrator\\Desktop\\out.txt","w",stdout);
#endif
//  ios_base::sync_with_stdio(0);
    int n;
    while(scanf("%d", &n) != EOF) {
        std::vector<int> xs;
        for(int i = 1; i <= n; i++) {
            int x;
            scanf("%d", &x);
            xs.push_back(x);
            a[i] = x;
        }
        sort(ALL(xs));
        xs.resize(unique(ALL(xs)) - xs.begin());
        for(int i = 1; i <= n; i++) {
            a[i] = lower_bound(ALL(xs), a[i]) - xs.begin() + 1;
        }

        // for(int i = 1; i <= n; i++) {
        //  printf("%d ", a[i]);
        // }
        // puts("");

        memset(pre, -1, sizeof pre);
        memset(nxt, -1, sizeof nxt);
        int big = xs.size();
        for(int i = 0; i <= n + 1; i++) {
            for(int j = i + 1; j <= n; j++) {
                if(nxt[i][a[j]] == -1) {
                    nxt[i][a[j]] = j;
                }
            }
            for(int j = i - 1; j > 0; j--) {
                if(pre[i][a[j]] == -1) {
                    pre[i][a[j]] = j;
                }
            }
        }
        for(int i = n; i > 0; i--) {
            dp[i][i] = sta(1, 1);
            sta ans = sta(0, 1);
            for(int j = i + 1; j <= n; j++) {
                dp[i][j] = sta(0, 0);
                if(a[i] == a[j]) {
                    // printf("dp[%d][%d] = %d %d\n", i, j, dp[i][j].first, dp[i][j].second);
                    dp[i][j] = sta(ans.first + 2, ans.second);
                }
                if(a[i] >= a[j]) {
                    int head = nxt[i][a[j]];
                    if(head == -1) continue;
                    if(dp[head][j].first > ans.first) {
                        ans = dp[head][j];
                    }
                    else if(dp[head][j].first == ans.first) {
                        int p = pre[j][a[j]];
                        if(p != -1 && dp[head][p].first == dp[head][j].first) ans.second -= dp[head][p].second;
                        if(ans.second < 0) ans.second += MOD;
                        ans.second = (ans.second + dp[head][j].second) % MOD;
                    }
                }
            }
        }
        sta ans(0, 0);
        for(int c = 1; c <= big; c++) {
            int head = nxt[0][c];
            int tail = pre[n+1][c];
            if(head == -1 || tail == -1) continue;
            // printf("dp[%d][%d] = %d\n", head, tail, dp[head][tail]);
            if(ans.first < dp[head][tail].first) {
                ans = dp[head][tail];
            }
            else if(ans.first == dp[head][tail].first) {
                ans.second = (ans.second + dp[head][tail].second) % MOD;
            }
        }
        printf("%d %d\n", ans.first, ans.second);
    }   

    return 0;
}

你可能感兴趣的:(动态规划)