Codeforces Round #750 (Div. 2) E. Pchelyonok and Segments

传送门

题目大意:

给一个序列,可以在这个序列中从左至右选若干个段,第i段的长度为i,对于任意的段i,段内元素和S[i]<S[i+1],求在该序列中最多可以选出几段。

思路:设dp[i][j]为从Ai个到第An个数中可以取j段满足条件时能达到的第一段sum的最大值

我们从后往前dp,一开始dp[N][1]=A[N],其他初始为0,当j=1时,显然有,dp[i][1]=max(A[i],dp[i+1][1])。

对于其他情况,设sum=A[i]+A[i+1]+...+A[i+j-1],如果dp[i+j][j-1] > 0 且 sum < dp[i+j][j-1](为了满足段的和必须递增,以及从A[i+j]开始取可以取j-1段),那么dp[i][j]=max(dp[i+1][j],sum),否则,dp[i][j]=dp[i+1][j]。

最后遍历所有dp[1][j],dp[1][j] > 0时即第一段和>0,说明可以取j段,最大的使dp[1][j] > 0的j即为答案。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int>PII;
#define INF 0x3f3f3f3f3f3f3f3f
#define inf 0x3f3f3f3f
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#pragma warning(disable:4996)
const int maxn = 101010;

LL T, N, A[maxn], S[maxn];
LL dp[maxn][510];//从Ai个到第An个数中可以取j段满足条件时能达到的第一段sum的最大值

void solve()
{
	for (int i = 1; i <= N; i++)
		S[i] = S[i - 1] + A[i];
	for (int i = 0; i <= N + 1000; i++)
	{
		for (int j = 0; j <= int(sqrt((N + 1) * 2)); j++)
			dp[i][j] = -INF;
	}
	int ans = 1;
	dp[N][1] = A[N];
	for (int i = N - 1; i > 0; i--)
	{
		dp[i][1] = max(dp[i + 1][1], A[i]);
		for (int j = 2; j <= int(sqrt((N + 1)*2)); j++)
		{
			dp[i][j] = dp[i + 1][j];
			LL sum = S[i + j - 1] - S[i - 1];
			if (dp[i + j][j - 1] > 0 && sum < dp[i + j][j - 1])
				dp[i][j] = max(dp[i][j], sum);
		//	cout << i << "-" << j << ":::::" << dp[i][j] << endl;
		}
	}
	for (int j = 2; j <= int(sqrt((N + 1) * 2)); j++)
	{
		if (dp[1][j] > 0)
			ans = j;
	}
	cout << ans << endl;
}

int main()
{
	IOS;
	cin >> T;
	while (T--)
	{
		cin >> N;
		for (int i = 1; i <= N; i++)
			cin >> A[i];
		solve();
	}

	return 0;
}

posted @ 2022-03-02 20:07  Prgl  阅读(24)  评论(0)    收藏  举报