1065 最小正子段和
N个整数组成的序列a[1],a[2],a[3],…,a[n],从中选出一个子序列(a[i],a[i+1],…a[j]),使这个子序列的和>0,并且这个和是所有和>0的子序列中最小的。
例如:4,-1,5,-2,-1,2,6,-2。-1,5,-2,-1,序列和为1,是最小的。
输入
第1行:整数序列的长度N(2 <= N <= 50000) 第2 - N+1行:N个整数
输出
输出最小正子段和。
输入样例
8 4 -1 5 -2 -1 2 6 -2
输出样例
1
解题思路:首先利用前缀和可以表示出所有的子串,通过for循环也可以遍历每一个子串,找出最小的正子串。
基本思路有了剩下的就是优化,通过对于前缀和的优化,,两种方式线段树,和树状数组,这个题显然树状数组比较合适,通过树状数组优化也降低不了整体的时间复杂度,毕竟还有两个for循环,N^2的复杂度,这里就要用到一个选择的方法了,我叫他SORT筛法。
sort筛法:通过sort排序将所有的字串排序,然后只考虑相邻的可以形成子串的进行选择。
sort筛选依据:通过排序之后形成ABC的形式,如果A不能和B形成字串,A和C可以形成,那么B和C也一定能形成字串,而且更优,如果A和B不能形成字串,就算是没有排序之前可以形成字串,形成的也是一个负值的子串。
#include <stdio.h>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <string.h>
#include <stdlib.h>
#include <vector>
#define CLE(a,b) memset(a,b,sizeof(a))
#define LL long long
using namespace std;
const int Maxn = 50005;
LL table[Maxn];
struct node{
LL val;
int id;
}resu[Maxn];
int n;
int lowbit(int x){
return x&(-x);
}
bool cmp(node a,node b){
return a.val<b.val;
}
void update(int x,LL add){
while(x<=n){
table[x]+=add;
x+=lowbit(x);
}
}
LL query(int x){
LL sum = 0;
while(x){
sum+=table[x];
x-=lowbit(x);
}
return sum;
}
void init(){
CLE(table,0);
for(int i=0;i<Maxn;i++){
resu[i].val = 0;
resu[i].id = 0;
}
}
int main(){
init();
LL smin = INT_MAX;
scanf("%d",&n);
for(int i=1;i<=n;i++){
int temp;
scanf("%d",&temp);
if(temp>0&&temp<smin)
smin = temp;
update(i,temp);
}
for(int i=1;i<=n;i++){
resu[i].val = query(i);
resu[i].id = i;
}
/*for(int i=1;i<=n;i++){
printf("##%d %d\n",resu[i].id,resu[i].val);
}*/
sort(resu,resu+n+1,cmp);
/*for(int i=0;i<=n;i++){
printf("##%d %d\n",resu[i].id,resu[i].val);
}*/
/*for(int i=1;i<n;i++){
if(resu[i].id<resu[i+1].id){
int temp = resu[i+1].val-resu[i].val;
if(temp<smin&&temp>0){
smin = temp;
//printf("%d %d\n",resu[i].id,resu[i+1].id);
}
}
else{
int temp = resu[i].val-resu[i+1].val;
if(temp<smin&&temp>0){
smin = temp;
// printf("#%d %d\n",resu[i].id,resu[i+1].id);
}
}
}
printf("%lld\n",smin);*/
int res = INT_MAX;
int flag = 0;
for (int i = 1; i <= n; i++)
{
if(resu[i].id-resu[i-1].id>0&& resu[i].val - resu[i - 1].val > 0)
{
if (flag == 0)
{
flag = 1;
res = resu[i].val - resu[i - 1].val;
}
else
{
if (resu[i].val - resu[i - 1].val < res)
{
res = resu[i].val - resu[i - 1].val;
}
}
}
}
printf("%d\n",res);
return 0;
}
筛选方式极为重要。