#189. 转啊转

来源:互联网 发布:国家统计局gdp数据 编辑:程序博客网 时间:2024/04/30 17:07

用f[i][j][i1][j1]表示序列中i到j,最小值为i1,最大值为j1的子序列最大长度。

先进行预处理:显然要令所有f[i][i][a[i]][a[i]]=1。

另外要注意预处理只有两个且a[i]<a[i+1]的情况,因为这种情况下的翻转下面是枚举不到的。

则有几种状态转移方式:

①直接继承:MAX(f[i][j+1][i1][j1],f[i][j][i1][j1]),MAX(f[i-1][j][i1][j1],f[i][j][i1][j1])。

②直接加入:if(a[j+1]>=j1)MAX(f[i][j+1][i1][a[j+1]],f[i][j][i1][j1]+1),if(a[i+1]<=i1)MAX(f[i-1][j][a[i]][j],f[i][j][i1][j1]+1)。

③考虑翻转:if(a[j+1]<=i1)MAX(f[i-1][j+1][a[j+1]][j1],f[i][j][i1][j1]+1),if(a[i-1]>=j1)MAX(f[i-1][j+1][i1][a[i-1]],f[i][j][i1][j1]+1),if(两者均成立)MAX(f[i-1][j+1][a[j+1]][a[i-1]],f[i][j][i1][j1]+2)

由于这题是多测,我们还要记得每次对f数组进行memset,好像我因为这个问题搞了很久。

这个代码长得不止一点丑:

#include<cstdio>#include<iostream>#include<algorithm>#include<queue>#include<vector>#include<cmath>using namespace std;#define rep(i,j,k) for(i=j;i<=k;++i)#define per(i,j,k) for(i=j;i>=k;--i)#define ll long long#define db double#define ldb long double#define pli pair<ll,int>#define mkp make_pair#define X first#define Y secondconst int N=52;int n,f[N][N][N][N],a[N],ans;void MAX(int &x,int y){x=max(x,y);}int main(){int i,j,h,i1,j1;while(~scanf("%d",&n)){rep(i,1,n)rep(j,i,n)rep(i1,1,n)rep(j1,1,n)f[i][j][i1][j1]=0;rep(i,1,n){scanf("%d",&a[i]);f[i][i][a[i]][a[i]]=1;}rep(i,2,n)if(a[i]<=a[i-1]){f[i-1][i][a[i]][a[i-1]]=2;}ans=0;rep(h,1,n){per(i,n-h+1,1){j=i+h-1;rep(i1,1,n){rep(j1,i1,n){MAX(f[i][j+1][i1][j1],f[i][j][i1][j1]);MAX(f[i-1][j][i1][j1],f[i][j][i1][j1]);if(a[j+1]>=j1)MAX(f[i][j+1][i1][a[j+1]],f[i][j][i1][j1]+1);if(a[i-1]<=i1)MAX(f[i-1][j][a[i-1]][j1],f[i][j][i1][j1]+1);if(a[j+1]<=i1)MAX(f[i-1][j+1][a[j+1]][j1],f[i][j][i1][j1]+1);if(a[i-1]>=j1)MAX(f[i-1][j+1][i1][a[i-1]],f[i][j][i1][j1]+1);if(a[j+1]<=i1&&a[i-1]>=j1)MAX(f[i-1][j+1][a[j+1]][a[i-1]],f[i][j][i1][j1]+2);}}}}rep(i,1,n)rep(j,i,n)MAX(ans,f[1][n][i][j]);printf("%d\n",ans);} return 0;}


0 0