位运算+滚动数组//前缀和+差分

题目描述

给出一个长度为 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^3n2×103。
  • 对于 100\%100% 的数据,保证 1 \leq n \leq 2 \times 10^51n2×105,-10^4 \leq a_i \leq 10^4104ai104。

代码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;//其实可以直接排序输出最大的即可;
}
posted @ 2022-03-05 17:05  清初  阅读(85)  评论(0)    收藏  举报