我们知道在最大值和最小值之外我们进行加减对答案是不影响的,而对于两个极值内部,我们一定会让他尽最大努力向一个方向走,因此我们可以把同一方向的放在一块。
但是我们不知道极值在哪里,只知道结构,所以我们循环整个取值去尝试找到最大值就好了,答案一定是其中之一的情况
/*input
3 100
1 2 -3
*/
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=3010;
int a[N],b;
int p[N];
ll mx(int n)
{
ll ans=0;
for(int i=0;i<b+1;i++)
{
ll l=0,r=0,idx=0,c=0;
for(int j=1;j<=n;j++)
{
if(a[j]) idx+=a[j];
else idx+=p[(c+i)%b],c++;
l=min(l,idx);
r=max(r,idx);
}
ans=max(ans,r-l+1);
}
return ans;
}
int main()
{
ll n,m;
ll sum=0;
cin>>n>>m;
for(int i=1;i<=n;i++) {
cin>>a[i]; sum+=a[i];
if(a[i]==0) b++;
}
if(abs(sum)>1ll*b*m)
cout<<-1<<endl;
else{
ll ans=0;
ll q=abs(sum);
for(int i=0;i<b;i++)
{
if(q+m<=(b-i-1)*m) p[i]=m,q+=m;
else if(q>0)
{
if(q%m==0) p[i]=-m,q-=m;
else p[i]=-q%m,q+=p[i];
}
if(sum<0) p[i]=-p[i];
}
ll test=sum;
for(int i=0;i<b;i++) test+=p[i];
if(test==0) ans=max(ans,mx(n));
for(int i=0;i<b;i++) p[i]=0;
q=abs(sum);
for(int i=0;i<b;i++)
{
if(m-q<=(b-i-1)*m) p[i]=-m,q-=m;
else if(q<0)
{
if(q%m==0) p[i]=m,q+=m;
else p[i]=-q%m,q+=p[i];
}
if(sum<0) p[i]=-p[i];
}
test=sum;
for(int i=0;i<b;i++) test+=p[i];
if(test==0) ans=max(ans,mx(n));
cout<<ans<<endl;
}
}

该博客主要探讨了一种算法问题,即在给定序列中寻找最大连续子段和。通过循环遍历和比较极值,确定最优解。算法涉及到最大值、最小值的处理,以及对序列结构的理解。代码实现包括了两种情况的处理,分别针对序列总和大于、小于或等于极值倍数的情况。最终输出可能的最大连续子段长度。
753

被折叠的 条评论
为什么被折叠?



