题意 给一个串,要求找出有多少个从里到外递增(不严格)的回文串序列(即可以分开的),最大长度是多少
做法:很容易想到维护一个n3的区间dp
dp[l][r] 更新是枚举c(c<=a[l]) dp[ nxt[l][c] ][ pre[r][c] ]
nxt[pos][c]代表pos位置向右第一个值为c的位置
pre[pos][c]代表pos位置向左第一个值为c的位置
但是会t
考虑n2优化
我们发现,如果固定l左端点,移动右端点,每次移动一次,nxt[l]这个数组在移动过程中是不会变的
pre[r]数组随着r->r+1,每次也只会变一个值,就是新加入的r+1
那么我们考虑先反着扫l,在正着搞r,这样扫过的所有子区间都被我提前处理过
从前到后维护一个ans最优解
做法:很容易想到维护一个n3的区间dp
dp[l][r] 更新是枚举c(c<=a[l]) dp[ nxt[l][c] ][ pre[r][c] ]
nxt[pos][c]代表pos位置向右第一个值为c的位置
pre[pos][c]代表pos位置向左第一个值为c的位置
但是会t
考虑n2优化
我们发现,如果固定l左端点,移动右端点,每次移动一次,nxt[l]这个数组在移动过程中是不会变的
pre[r]数组随着r->r+1,每次也只会变一个值,就是新加入的r+1
那么我们考虑先反着扫l,在正着搞r,这样扫过的所有子区间都被我提前处理过
从前到后维护一个ans最优解
每次到达r时,枚举的那个c应该是越来越优的,所以我只需要把原来的pre[r][a[r]]的影响(如果有)减掉。再加上r的影响即可
#pragma comment(linker,"/STACK:1024000000,1024000000")
#include <cstdio>
#include <cstring>
#include <vector>
#include <cstdlib>
#include <stack>
#include <algorithm>
#include <queue>
#include <map>
#define xx first
#define yy second
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
ll dp[5005][5005], f[5005][5005];
int nxt[5005][5005], pre[5005][5005];
ll a[5005];
pair<ll,int>san[5005];
int main()
{
int n, i, j, m, l, r;
freopen("in.in", "r", stdin );
while(~scanf("%d", &n)){
for( i = 1; i <= n; i ++ ){
scanf("%I64d", &a[i]);
san[i].xx = a[i];
san[i].yy = i;
}
sort( san+1, san+1+n );//离散化
int cnt = 0;
san[0].xx = -1;
for( i = 1; i <= n; i ++ ){
if( san[i].xx != san[i-1].xx ) cnt ++;
a[ san[i].yy ] = cnt;
}
//for( i = 1; i <= n; i ++ ) printf("%I64d ", a[i]);
a[0] = a[n+1] = cnt+1;
memset( dp, -1, sizeof(dp) );
memset( nxt, 0, sizeof(nxt) );
memset( pre, 0, sizeof(pre) );
for( i = 0; i <= n+1; i ++ ){
for( j = i+1; j <= n+1; j ++ ){
if( !nxt[i][a[j]] ) nxt[i][a[j]] = j;
}
for( j = i-1; j >= 0; j -- ){
if( !pre[i][a[j]] ) pre[i][a[j]] = j;
}
}
for( l = n+1; l >= 0; l -- ){// 倒过来搞
ll ans1 = 0, ans2 = 1;
for( r = l; r <= n+1; r ++ ){
ll tmp1, tmp2;
if( l == r ){
dp[l][r] = 1;
f[l][r] = 1;
continue;
}
if( a[r-1] <= a[l] ){
tmp1 = dp[ nxt[l][a[r-1]] ][ pre[r-1][a[r-1]] ];
tmp2 = f[ nxt[l][a[r-1]] ][ pre[r-1][a[r-1]] ];
if( ans1 == tmp1 ){
ans2 = ans2-tmp2+mod;
ans2 %= mod;
}
if( ans1 < tmp1 ){
ans1 = tmp1;
ans2 = tmp2;
}//在更新之前,我必须先去除前一个右边为a[r]的留下的影响
tmp1 = dp[ nxt[l][a[r-1]] ][ r-1 ];
tmp2 = f[ nxt[l][a[r-1]] ][ r-1 ];
if( ans1 == tmp1 ){
ans2 += tmp2;
ans2 %= 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] = 0, f[l][r] = 0;
}
}
ll ans1 = 1, ans2 = 1;
// for( i = 1; i <= n; i ++ ){
// for( j = i; j <= n; j ++ ){
// printf("dp %d %d %I64d %I64d\n", i, j, dp[i][j], f[i][j]);
// }
// }
for( i = 1; i <= cnt; i ++ ){
if( dp[ nxt[0][i] ][ pre[n+1][i] ] > ans1 ){
ans1 = dp[ nxt[0][i] ][ pre[n+1][i] ];
ans2 = f[ nxt[0][i] ][ pre[n+1][i] ];
}
else if( ans1 == dp[ nxt[0][i] ][ pre[n+1][i] ] ){
ans2 += f[ nxt[0][i] ][ pre[n+1][i] ];
ans2 %= mod;
}
}
printf("%I64d %I64d\n", ans1, ans2);
}
}