这次给大家讲道题,废话不多说,上题:题目描述
一个长度为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;
}
谢谢!