打个广告:
洛谷博客:文章列表 - JunhanWang 的博客 - 洛谷博客
CSDN:CSDN
----------------------------------------------一刀不怎么华丽的分割线--------------------------------------------------
题解正式开始: 首先,这道题第一思路就是枚举从 L到 R的最大和,代码大概是定义一个CNT,从1到i,循环从1到i,长度不断增加,再比较一下就好啦,大概是O(n²)级别的,会超一点点
还有,就可以分治,所谓分治就是“分而治之”,把一个大问题划分成小问题,可以练习P1010和P1024。
分治思路:首先,假定有区间l~r,其中间位置为mid,其最大子段为[i..j]。有三种情况
只需要分别求出三种情况下的值,取其最大的即可。
那么,只需递归求出即可。
上代码
#include<bits/stdc++.h>
int n , arr[200200];
const int minn = -19260817;
int rec( int l , int r ) {
if ( l == r ) {
return arr[l];
}
int mid = ( l + r ) >> 1;
int sum = 0 , ret1 = minn , ret2 = minn;
for( int i = mid ; i >= l ; i-- ) {
sum += arr[i];
ret1 = Max( ret1 , sum );
}
sum = 0;
for( int i = mid+1 ; i <= r ; i++ ) {
sum += arr[i];
ret2 = Max( ret2 , sum );
}
}
int main() {
scanf("%d", &n );
for( int i = 1 ; i <= n ; i++ ) {
scanf("%d" , &arr[i] );
}
printf("%d" , rec(1 , n) );
return 0;
}
其实,这道题还可以用贪心做。
方法如下:要不选,要不自己是一类 比如 -1 -2 9
-1要选自己,因为前面没有数
-2要选自己,因为前面的数,-1+-2=-3 小于-2
9要选自己,因为9>9-3
上代码:
#include<bits/stdc++.h>
using namespace std;
int n,j,sum,maxx;
int main(){
scanf("%d%d",&n,&maxx)
while(--n)
{
scanf("%d",&j);
sum=sum>0?sum:0;
sum+=j;
maxx=maxx>sum?max:sum; //直接复制有惊喜呦
}
return (printf("%d",maxx));
}
纯正的DP做法: 首先,通过题意,我们可以了解到:
f[i]=max(f[i-1]+n[i],n[i])
但是!
f[n]的值并不一定是最终结果
比如这个输入:
5 233 233 -666 1 1
如果直接输出f[n]的值,结果会是2,但是答案应该为466!
为什么?
因为若f[i]的值为负数,则f[i+1]的值就是n[i],而n[i]的值不一定比前面的最大字段和数大!
(或者n[i]为负数,则f[i]小于f[i-1]!)
所以,我们还要再用一个数从1到n再查找一次,才能找出最大数
代码:
#include<bits/stdc++.h>
using namespace std;
int n[200001],p,ans[200001]={0};
const int INF=0x3f3f3f3f;
int main()
{
int sum=-INF;
cin>>p;
for(int i=0;i<p;i++)
{
cin>>n[i];
ans[i]=max(ans[i-1]+n[i],n[i]);
sum=max(sum,ans[i]);
}
cout<<sum;
}
好了,这道题就讲到这里,希望大家CSP_J/S能得到好分数.