Codeforces Round #750 (Div. 2)  E. Pchelyonok and Segments  (dp)_取值

  • 题意:长度为\(n\)的数组,确定一个数\(k\),然后连续选\(k,k-1,...,2,1\)个不相交的区间,并且满足区间\(sum\)和严格递增,问你\(k\)的最大取值。

  • 题解:我们从后往前遍历,设\(dp[k][i]\)表示当前位置为\(i\),选择区间长为\(k\)\([i,n]\)中的最大取值,因为我们要求区间是严格递增的,所以取最大最优,那么如果不选当前这个区间,则:\(dp[k][i]=max(dp[k][i+1],...,dp[k][n-k+1])\),如果选择当前这个区间,我们要先判断一下当前区间和是否小于\(dp[k-1][i+k]\),然后再维护最大值:\(dp[k][i]=max(dp[k][i],sum[i+k-1]-sum[i-1])\).

    最后还要注意\(dp\)数组的初始值。卡了我好久(

  • 代码

    #include <bits/stdc++.h>
    #define ll long long
    #define fi first
    #define se second
    #define pb push_back
    #define me memset
    #define rep(a,b,c) for(int a=b;a<=c;++a)
    #define per(a,b,c) for(int a=b;a>=c;--a)
    const int N = 1e6 + 10;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    using namespace std;
    typedef pair<int,int> PII;
    typedef pair<ll,ll> PLL;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
    
    ll dp[501][100010];
    
    int main() {
    	int _;
    	scanf("%d",&_);
    	while(_--){
    		int n;
    		scanf("%d",&n);
    		for(int k=1;k<=500;++k){
    			for(int i=1;i<=n+1;++i){
    				dp[k][i]=0;
    			}
    		}
    		vector<int> a(n+1);
    		vector<ll> sum(n+1);
    		for(int i=1;i<=n;++i){
    			scanf("%d",&a[i]);
    			sum[i]=sum[i-1]+a[i];
    		}
    		for(int i=1;i<=n+1;++i){
    			dp[0][i]=INF;
    		}
    		for(int i=n;i>=1;--i){
    			for(int k=1;k<=500;++k){
    				dp[k][i]=dp[k][i+1];
    				if(i+k-1<=n && sum[i+k-1]-sum[i-1]<dp[k-1][i+k]){
    					dp[k][i]=max(dp[k][i],sum[i+k-1]-sum[i-1]);
    				}
    			}
    		}
    		int ans;
    		for(int i=500;i>=1;--i){
    			if(dp[i][1]){
    				ans=i;
    				break;
    			}
    		}
    		printf("%d\n",ans);
    	}
        return 0;
    }
    
???????????????????????????????????????????? ???????????????????????????????? ???????????? ???????????????? ???????????????? ???????????????????????????????? ???????? ????????????????