题目大意:经典的最大连续子序列和
思路:本来是今天开始学点DP的,但是就是一些经典DP例子还是要先掌握啊~~不过学长说这道题如果认真的用DP来解释的话算是很难的题目的~~是不是我就很难考证了~~不过我反正知道~~如果不是提前有思路的话~~我相信没几个人会把这道题当做水题~~有了思路~~就水过了~~因为DP的编码一向都是很简洁的~~只不过我的编码能力还是暴虐全场啊~~只不过是被题目虐的那一种啊~~囧。。不过我更多的感觉是自己模拟过的~~囧。。
状态方程 sum[i] = sum[i - 1] > 0 ? sum[i - 1] + a[i] : a[i] 下标做得我很恶心~~编码能力啊~~求给力啊~~
关键思路:tmp:在序列中的求和。 sum:保存MAX。 每次tmp<0的时候就要令其为0,从新开始,在这里设立一个变量保存变动的起点很重要。起点在tmp更新为0的时候就设立为i+1(下一个位置的关系),当然这种设立情况要特殊处理n==1和全部为负数的特殊情况。如果tmp>sum的时候,那么终点指针更新,此时顺便更新起始位置的指针是因为刚开始的时候tmp还没大于sum,但是虽然我的剑掉在河里面了,但是我已经拿了一个竹竿插在那了,此时的更新是我如果知道tmp>sum了的话,就在本子上记上这个最新竹竿。
AC program:
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#define oo -10000000
using namespace std;
int mm[100005];
int main()
{
int test;
cin>>test;
int cas=1;
while(test--)
{
if(cas>=2)cout<<endl;
int n;
memset(mm,0,sizeof(mm));
cin>>n;
for(int i=0;i<n;i++)
{
cin>>mm[i];
}
if(n==1) //特殊情况一
{
cout<<"Case "<<cas++<<':'<<endl; //输出感觉很恶心,要不是我开始用cin了,早就scanf printf了。囧
cout<<mm[0]<<' '<<1<<' '<<1<<endl;
continue;
}
int tmppp=oo;
int tag,kg=0; //特殊情况二
for(;kg<n;kg++)
{
if(mm[kg]>0)
break;
if(mm[kg]>tmppp)
{
tmppp=mm[kg];
tag=kg;
}
}
if(kg==n)
{
cout<<"Case "<<cas++<<':'<<endl;
cout<<tmppp<<' '<<tag+1<<' '<<tag+1<<endl;
continue;
}
int sum=0,tmp=0,ffs=0,fs,fl; //一般情况
for(int i=0;i<n;i++)
{
tmp+=mm[i];
//cout<<"tmp "<<tmp<<endl;
if(tmp<0)//
{
ffs=i+1; //ffs这个变动的起点下标很重要
tmp=0;
}
else if(tmp>sum) //小于0的时候就另外开始,
//对于新的一堆数如果有更大的话,
//那么最好的是既保存了以往的开始下标有保存了现在的开始下标
//一旦新的一堆更大的时候,就把以往的开始下标更新为现在的开始下标
{
sum=tmp;
fs=ffs;
fl=i;
}
}
cout<<"Case "<<cas++<<':'<<endl;
cout<<sum<<' '<< fs+1<<' '<<fl+1<<endl;//数组下标加上1得到位置
}
//system("pause");
return 0;}