P2642 双子序列最大和
题目描述
给定一个长度为n的整数序列,要求从中选出两个连续子序列,使得这两个连续子序列的序列和之和最大,最终只需输出最大和。一个连续子序列的和为该子序列中所有数之和。每个连续子序列的最小长度为1,并且两个连续子序列之间至少间隔一个数。
输入输出格式
输入格式:第一行是一个整数表示n。
第二行是n个整数表示整数序列。
输出格式:一个数,两个连续子序列的序列和之和。
输入输出样例
说明
对于30%的数据N<=100。
对于60%的数据有N<=10000。
对于100%的数据有N<=1000000。
扫描二维码关注公众号,回复:
2169129 查看本文章
数据保证运算过程不会超过long long(int64)。
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
#define MAXN 1000100
int n;
int a[MAXN];
int dp1[MAXN],dp2[MAXN];
#define INF 0x3f3f3f3f
int ans_left[MAXN],ans_right[MAXN];
int ans=0;
int main()
{
int i;
scanf("%d", &n);
memset(dp1,0,sizeof(dp1));
memset(dp2,0,sizeof(dp2));
int ans=-INF;
ans_left[0]=-INF;
ans_right[n+1]=-INF;
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
for(i=1;i<=n;i++)
{
dp1[i]=max(dp1[i-1]+a[i],a[i]);
ans_left[i]=max(ans_left[i-1],dp1[i]);//到i为止,最大的连续子段
}
for(i=n;i>=1;i--)
{
dp2[i]=max(dp2[i+1]+a[i],a[i]);
ans_right[i]=max(ans_right[i+1],dp2[i]);
}
for(i=2;i<=n-1;i++)
{
ans=max(ans_left[i-1]+ans_right[i+1],ans);//因为每次都是最大,算间隔为2一定是小了,所以只要考虑间隔为1的情况,间隔为1就是相差为2
}
printf("%d\n",ans);
return 0;
}
P1121 环状最大两段子段和
题目描述
给出一段环状序列,即认为 A_1A1 和 A_NAN 是相邻的,选出其中连续不重叠且非空的两段使得这两段和最大。
输入输出格式
输入格式:第一行是一个正整数 N(N\le 2\times 10^{5})N(N≤2×105) ,表示了序列的长度。
第二行包含 NN 个绝对值不大于 1000010000 的整数 A_iAi ,描述了这段序列,第一个数和第 NN 个数是相邻的。
输出格式:一个整数,为最大的两段子段和是多少。
输入输出样例
说明
【样例说明】
一段为 33 。
/*(1)没形成环000111000111000
(2)成环111000111000111 */
//两种情况的处理
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
#define MAXN 1000100
int n;
int a[MAXN];
int dp1[MAXN],dp2[MAXN];
#define INF 0x3f3f3f3f
int ans_left[MAXN],ans_right[MAXN];
int ans1=-INF,ans2=INF;
int main()
{
int i;
int sum=0;
scanf("%d", &n);
memset(dp1,0,sizeof(dp1));
memset(dp2,0,sizeof(dp2));
int ans=-INF;
ans_left[0]=-INF;
ans_right[n+1]=-INF;
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum+=a[i];
}
for(i=1;i<=n;i++) //(1)没形成环000111000111000
{
dp1[i]=max(dp1[i-1]+a[i],a[i]);
ans_left[i]=max(ans_left[i-1],dp1[i]);//到i为止,最大的连续子段
}
for(i=n;i>=1;i--)
{
dp2[i]=max(dp2[i+1]+a[i],a[i]);
ans_right[i]=max(ans_right[i+1],dp2[i]);
}
for(i=1;i<=n-1;i++)
{
ans1=max(ans_left[i]+ans_right[i+1],ans1);//因为每次都是最大,算间隔为2一定是小了,所以只要考虑间隔为1的情况,间隔为1就是相差为2
}
memset(dp1,0,sizeof(dp1));
memset(dp2,0,sizeof(dp2));
memset(ans_left,0,sizeof(ans_left));
memset(ans_right,0,sizeof(ans_right));
ans_left[0]=INF;
ans_right[n+1]=INF;
for(i=1;i<=n;i++) //(2)成环111000111000111
{
dp1[i]=min(dp1[i-1]+a[i],a[i]);
ans_left[i]=min(ans_left[i-1],dp1[i]);//到i为止,最大的连续子段
}
for(i=n;i>=1;i--)
{
dp2[i]=min(dp2[i+1]+a[i],a[i]);
ans_right[i]=min(ans_right[i+1],dp2[i]);
}
for(i=1;i<=n-1;i++)
{
ans2=min(ans_left[i]+ans_right[i+1],ans2);//间隔为0的情况。
}
if(sum!=ans2)
ans2=sum-ans2; //考虑到特殊情况,全为负数的时候(取最小的时候所有数都可以取,sum0-ans2=0,而ans1=sum,为负,ans==0,错误,所以这步
ans=max(ans1,ans2);
printf("%d\n",ans);
return 0;
}