这道题我们发现数据范围并不大,而且最重要的一点是,可以看的出区间dp的影子,也就是说长区间的最大值,完全可以通过两个小区间合并而来
因此我们考虑先暴力枚举每个区间的lis。之后进行区间dp计算
有几个注意点是,初始化的时候,只需要初始化长度至少为1的情况,在区间dp内部,有一步赋值操作
这一步的意义是将我们求出的符合条件的lis赋值给这段区间,这样可以保证正确性,因为这道题是大于等于k的最多个数,所以答案并不一定是合并而来,比如 1 3 5 他的k=2的答案其实是3
这也是我们要求lis的原因
#include<iostream> #include<cstring> #include<cstdio> #include<map> #include<algorithm> #include<queue> #include<set> #define ull unsigned long long using namespace std; typedef long long ll; typedef pair<int,int> pll; typedef pair<int,pair<int,int> > plll; const int N=1e5+10; const int inf=0x3f3f3f3f; using namespace std; int f[201][201][201]; int a[N]; int cnt[201][201]; int lis(int l,int r){ vector<int> num; int i,j; num.push_back(a[l]); for(i=l+1;i<=r;i++){ if(a[i]>num.back()) num.push_back(a[i]); else{ int pos=lower_bound(num.begin(),num.end(),a[i])-num.begin(); num[pos]=a[i]; } } return num.size(); } int main() { int i; int t; cin>>t; while(t--){ int n; cin>>n; for(i=1;i<=n;i++){ cin>>a[i]; } int j; for(i=1;i<=n;i++){ for(j=1;j<=n;j++){ cnt[i][j]=lis(i,j); } } memset(f,0,sizeof f); for(i=1;i<=n;i++){ f[1][i][i]=1; } int l,r; int len; for(i=1;i<=cnt[1][n];i++){ for(len=1;len<=n;len++){ for(l=1;l+len-1<=n;l++){ r=l+len-1; if(cnt[l][r]>=i){ f[i][l][r]=cnt[l][r]; } int k; for(k=l;k<r;k++){ f[i][l][r]=max(f[i][l][r],f[i][l][k]+f[i][k+1][r]); } } } } for(i=1;i<n;i++){ printf("%d ",f[i][1][n]); } cout<<f[n][1][n]<<endl; } }