我的题解(1)-最大连续和

这次给大家讲道题,废话不多说,上题:

题目描述

一个长度为n数组A的最大连续和,是指所有满足1≤L≤R≤n的L和R中A[L]+A[L+1]+...+A[R]的最大值。
一次交换操作是指:
(1) 选择两个下标i和j(i ≠ j)
(2)进行赋值,tmp=A[i];A[i]=A[j],A[j]=tmp;
给定一个长度为n的数字,最多进行m次交换操作后,该数组的最大连续和。
 

输入

第一行两个两个整数n和m。
第二行n个数字,表示数组中的元素。
 

输出

输出题目要求的答案。

样例输入

10 2
10 -1 2 2 2 2 2 2 -1 10
5 10
-1 -1 -1 -1 -1

样例输出

32
-1

范围

【数据范围】
对于前20% 的数据,m的值为0;
对于前30% 的数据,m的范围[0,1];
对于前40% 的数据,n的范围 [1,100],m的范围[0,10];
对于前50% 的数据,n的范围 [1,200],m的范围[0,20];
对于前60% 的数据,n的范围 [1,300],m的范围[0,30];
对于前70% 的数据,n的范围 [1,500],m的范围[0,50];
对于前90% 的数据,n的范围 [1,1000],m的范围[0,100];
对于前100% 的数据,n的范围 [1,1100],m的范围[0,100];

首先,我们明确最大连续和怎么求:

int i=1,sum,ans=-INF;
while(i<=n){
	sum=0;
	for(j=i;j<=n;j++){
		sum+=a[j];
		ans=max(ans,sum);
		if(sum<0) break;
	}
	i=j+1;
}
return ans;

如果有序列a1,...,an

j一直往后移动,记录[i,j]区间的和。

如果∑ai,...,aj>0,那么∑ai,...,a[j+1]>a[j+1],直接累加a[j+1]

如果∑ai,...,aj<0,那么∑ai,...,a[j+1]<a[j+1],清零sum,i=j+1,j再开始循环。

于是,我一开始就是这样写的:

#include<bits/stdc++.h>
using namespace std;
const int oo=-0x3F3F3F3F;
int n,m,a[1101],f[1101][101];
int solve(int x,int y,int a[]){
	int i,j,p=oo;
	if(x==0||y==0){
		i=1;
		int sum;
		while(i<=n){
			sum=0;
			for(j=i;j<=n;j++){
				sum+=a[j];
				p=max(p,sum);
				if(sum<0) break;
			}
			i=j+1;
		}
		return p;
	}
	for(i=1;i<=x-1;i++){
		int t;
		t=a[i];
		a[i]=a[x];
		a[x]=t;
		p=max(p,solve(x-1,y-1,a));
		t=a[i];
		a[i]=a[x];
		a[x]=t;
	}
	p=max(p,solve(x-1,y,a));
	return p;
}
int main(){
	freopen("mx.in","r",stdin);
	freopen("mx.out","w",stdout);
	int i,j,k;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++) scanf("%d",&a[i]);
	printf("%d",solve(n,m,a));
	fclose(stdin);fclose(stdout);
	return 0;
}

(勿喷)
结果:AAATTTTTTT

......

好吧,只对三个点,太慢了。


改进后基本思路是:

枚举区间。[i,j]内计算和,为最大连续和。

其余的不要。

要使[i,j]中最大,那么:

sort[i,j];记为a[]

sort(combine[1,i-1]and[j+1,n]);记为b[]

i=1,j=1;

while(i,j未越界&&a[i]<b[j])

    swap(a[i],b[j]);


大概就是这个思路了。

可是时间复杂度为:

 n(枚举i)

*n(枚举j)

*n㏒₂n(sort)

=O(n³㏒₂n)

100%的话

大约是10000000000

100分和你再见

不行


现在有一种方法,可以降到O(n³)

也就是可以撑过去100

我们模拟插入排序的其中一些操作

首先,ij枚举不可缺少,但内循环里可以开两个数组,

一个数组用来存刚刚所说的[i,j](里面的计算和,作为最大连续和,记作a1),另一个存[1,i-1]与[j+1,n]的合并(记作a2)。

一开始,a1空,a2存[1,n];

每次从a2中调一个到a1,这一步模拟了扩大区间。

但是这一步模拟插入,保持有序。

然后,将区间外与区间内的值互换

也就是

while(i,j未越界&&a1[i]<a2[j])

    swap(a1[i],a2[j]);

注:这里的交换并不是直接交换,而是计算两者差值,加到sum里,否则就影响了接下来的有序性。

最后ans取大值。

搞定!!!

代码来了:

#include<bits/stdc++.h>
using namespace std;
const int oo=-0x3F3F3F3F;
int n,m,a[1101],a1[1101],a2[1101],l1,l2,x1,x2,sum,p,ans=oo,t;
int main(){
    freopen("mx.in","r",stdin);
    freopen("mx.out","w",stdout);
    int i,j,k;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++) scanf("%d",&a[i]);
    for(i=1;i<=n;i++){
        l1=0,l2=n,sum=0;
        for(j=1;j<=n;j++)
            a2[j]=a[j];
        sort(a2+1,a2+1+n);
        for(j=i;j<=n;j++){
            sum=0;
            for(k=1;k<=l2;k++) if(a2[k]==a[j]) break;
            p=k;
            for(k=p+1;k<=l2;k++) a2[k-1]=a2[k];
            int key=a[j];
            t=l1;
            while(t>0&&a1[t]>key){
                a1[t+1]=a1[t];
                t--;
            }
            l1++,l2--;
            a1[t+1]=key;
            for(k=1;k<=l1;k++) sum+=a1[k];
            x1=1,x2=l2,t=0;
            while(t<m&&x1<=l1&&x2>=1&&a1[x1]<a2[x2]){
                sum+=(a2[x2]-a1[x1]);
                t++,x1++,x2--;
            }
            ans=max(ans,sum);
        }
 
    }
    printf("%d",ans);
    fclose(stdin);fclose(stdout);
    return 0;
}
谢谢!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值