UCF Local Programming Contest 2017 H题(区间dp)

这道题我们发现数据范围并不大,而且最重要的一点是,可以看的出区间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;
    }
}
View Code
原文地址:https://www.cnblogs.com/ctyakwf/p/12663504.html