位运算+滚动数组//前缀和+差分
题目描述
给出一个长度为 nn 的序列 aa,选出其中连续且非空的一段使得这段和最大。
输入格式
第一行是一个整数,表示序列的长度 nn。
第二行有 nn 个整数,第 ii 个整数表示序列的第 ii 个数字 a_iai。
输出格式
输出一行一个整数表示答案。
输入输出样例
输入 #1
7 2 -4 3 -1 2 -4 3
输出 #1
4
说明/提示
样例 1 解释
选取 [3, 5][3,5] 子段 \{3, -1, 2\}{3,−1,2},其和为 44。
数据规模与约定
- 对于 40\%40% 的数据,保证 n \leq 2 \times 10^3n≤2×103。
- 对于 100\%100% 的数据,保证 1 \leq n \leq 2 \times 10^51≤n≤2×105,-10^4 \leq a_i \leq 10^4−104≤ai≤104。
代码1:
方法:位运算+滚动数组
#include<bits/stdc++.h>
using namespace std;
int n,a,b[2],i,ans=-2147483647;
// b数组用于存储序列和。
int main(){
cin>>n;
for(i=1;i<=n;i++){
cin>>a;//将数组优化为一个变量
if(i<2) b[1]=a;
else b[i&1]=max(a,b[!(i&1)]+a);//前面推导的步骤,配合滚动数组食用
ans=max(ans,b[i&1]);//更新答案
}
cout<<ans;
return 0;
/*
*
* 这里说一下代码里的位运算,&1 可以看做是 %2 。
* 而加上感叹号就是 0变1 , 1变0
*
*/
}
代码2:
方法:前缀和+差分;
c[i]表示的是a数组从头加到i的和~
b[i]表示的是从头到i包括i的的最大子段和~(必须包括i!!!)
minn储存最小的前缀和(因为要减去所以要尽量小,详情见下一行)~
动态转移方程式:b[i]=c[i]-minn(总和减去前缀和)~
mann是最后输出b数组最大的值(题目求最大的子段和)~
--------------------------------------------------------(划重点!!!)
minn一定要初始化成0!!!
如果设成a[1]会死……(如果是正数会减去正数,正解是不减,就是没有减去的子段和)
相反mann要设成很小的值!!!(废话)
--------------------------------------------------------(代码分割线)
#include<iostream>
using namespace std;
int n,a[200001]={0},b[200001]={0},c[200001]={0},minn=0,mann=-99999;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
c[i]=c[i-1]+a[i];
}
b[1]=a[1];minn=min(0,c[1]);
for(int i=2;i<=n;i++)
{
b[i]=c[i]-minn;
minn=min(minn,c[i]);
}
for(int i=1;i<=n;i++) mann=max(mann,b[i]);
cout<<mann<<endl;//其实可以直接排序输出最大的即可;
}

浙公网安备 33010602011771号