luogu P3607 [USACO17JAN]Subsequence Reversal P
题面传送门
这居然是一道P组题/jy
首先这道题要求LCS,很好啊,我啪的一下很快啊一个dp套dp扔上去了,如果你想到这边去就死定了。
实际上反转一个子序列一定是偶数个,因为如果反转奇数个中间那个相当于没动,可以规约到偶数个。
那么这个可以看作交换序列中的一些位置,满足这些位置两两之间存在包含关系。
包含关系想到区间dp,正好\(n\)灰常小,于是可以设计一个四维状态:设\(dp_{i,j,x,y}\)表示区间\([i,j]\),上升子序列头尾是\(x\)与\(y\),最长上升子序列是多少。
那么正常序列正常一步一步转移,需要反转的序列无论算不算入答案都要头尾各减去一个。
时间复杂度\(O(n^4)\)反正能跑过就是了。
code:
#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define ll long long
#define db double
#define lb long db
#define N (50+5)
#define M (200000+5)
#define K (350)
#define mod 1000000007
#define Mod (mod-1)
#define eps (1e-9)
#define ull unsigned ll
#define it iterator
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((k+1)*(x)+(y))
#define R(n) (1ll*rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using namespace std;
int n,m,k,Mx,dp[N][N][N][N],A[N],Ans;
int main(){
freopen("1.in","r",stdin);
int i,j,x,y;scanf("%d",&n);for(i=1;i<=n;i++) scanf("%d",&A[i]),Mx=max(Mx,A[i]);
for(i=n;i;i--){
dp[i][i][A[i]][A[i]]=1;for(j=i+1;j<=n;j++){
for(x=1;x<=Mx;x++) for(y=x;y<=Mx;y++) dp[i][j][x][y]=max(dp[i+1][j][x][y],dp[i][j-1][x][y]);
for(x=A[i];x<=Mx;x++) for(y=x;y<=Mx;y++) dp[i][j][A[i]][y]=max(dp[i][j][A[i]][y],dp[i+1][j][x][y]+1);
for(y=1;y<=A[j];y++) for(x=1;x<=y;x++) dp[i][j][x][A[j]]=max(dp[i][j][x][A[j]],dp[i][j-1][x][y]+1);
for(x=A[j];x<=Mx;x++) for(y=x;y<=Mx;y++) dp[i][j][A[j]][y]=max(dp[i][j][A[j]][y],dp[i+1][j-1][x][y]+1);
for(y=1;y<=A[i];y++) for(x=1;x<=y;x++) dp[i][j][x][A[i]]=max(dp[i][j][x][A[i]],dp[i+1][j-1][x][y]+1);
for(x=A[j];x<=Mx;x++) for(y=x;y<=A[i];y++) dp[i][j][A[j]][A[i]]=max(dp[i][j][A[j]][A[i]],dp[i+1][j-1][x][y]+2);
}
}for(x=1;x<=Mx;x++) for(y=x;y<=Mx;y++) Ans=max(Ans,dp[1][n][x][y]);printf("%d\n",Ans);
}