1. 程式人生 > >Palindrome Bo (預處理 + 區間DP)

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\n",ans1, ans2); } return 0; }