洛谷P5745 【深基附B例】区间最大和
题目链接:https://www.luogu.com.cn/problem/P5745
题目描述
给定 n 个正整数组成的数列 a1,a2,⋯,an 和一个整数 m。求出这个数列中的一个子区间 [i, j],也就是在这个数列中连续的数字 a_i, a_{i + 1},a_{j - 1}, a_jai,ai+1,⋯,aj−1,aj,使得这个子区间的和在不超过 m的情况下最大。如果有多个区间符合要求,请输出 ii 最小的那一个。
输入格式
输入共两行。
第一行,两个整数 n, m;
第二行,n 个整数1,a2,⋯,an。
输出格式
一行,三个整数,表示符合题意的区间的左端点、右端点和累加和。
输入输出样例
输入
5 10 2 3 4 5 6
输出
1 3 9
说明/提示
子任务 1(10分):n≤200 ;
子任务 2(20分):n≤3000 ;
子任务 3(30分):n≤10^5 ;
子任务 4(40分):n≤4×10^6 。
对于 100% 的数据,1 ≤n≤4×10^6,1≤m≤10^9
解题思路:
看起来不难但是很容易TLE 所以我们一步一步减小时间复杂度
10分代码:
很容易想到枚举所有的i到j,再对i到j进行求和,再判断是否满足条件,满足就更新答案。
时间复杂度O(n^3)
#include <bits/stdc++.h>
using namespace std;
int n,m;
int a[4000001];
int ans1,ans2,ans3;
int main(){
cin>>n>>m;
for(int i=1; i<=n; i++){//读入
scanf("%d",&a[i]);
}
for(int i=1; i<=n; i++){
for(int j=i; j<=n; j++){//枚举i与j
int sum=0;
for(int k=i; k<=j; k++){//求和
sum+=a[k];
}
if(sum>ans3&&sum<=m){//如果这个答案比以前的更优,则更新答案
ans1=i;
ans2=j;
ans3=sum;
}
}
}
cout<<ans1<<" "<<ans2<<" "<<ans3;//输出
}
30分代码:
因为要对区间进行求和,自然就会想到前缀和来维护。
我们记sumi=a1+a2+......+ai
则al+al+1+......ar=sumr−sum(l−1)
在读入的过程中预处理前缀和
时间复杂度:O(n^2)
代码:
#include <bits/stdc++.h> using namespace std; int n,m; int a[4000001]; int sum[4000001];//用sum数组来记录前缀和 int ans1,ans2,ans3; int main(){ cin>>n>>m; for(int i=1; i<=n; i++){ scanf("%d",&a[i]); sum[i]=sum[i-1]+a[i];//处理前缀和 } for(int i=1; i<=n; i++){ for(int j=i; j<=n; j++){ int cnt=sum[j]-sum[i-1]; if(cnt>ans3&&cnt<=m){//计算前缀和并更新答案 ans1=i; ans2=j; ans3=cnt; } } } cout<<ans1<<" "<<ans2<<" "<<ans3; }
60分代码:
因为所有的ai都是正整数,故sum单调递增。
所以若sumr−sum(l−1)>m,
因为sumr+1>sumr
故sumr+1−suml−1>m
后面的sumr+k−suml−1>m
所以就可以break了
时间复杂度:O(n^2)+小常数
代码:
#include <bits/stdc++.h> using namespace std; int n,m; int a[4000001]; int sum[4000001]; int ans1,ans2,ans3; int main(){ cin>>n>>m; for(int i=1; i<=n; i++){ scanf("%d",&a[i]); sum[i]=sum[i-1]+a[i]; } for(int i=1; i<=n; i++){ for(int j=i; j<=n; j++){ int cnt=sum[j]-sum[i-1]; if(cnt>ans3&&cnt<=m){ ans1=i; ans2=j; ans3=cnt; } if(cnt>m) break;//如果比m大就可以退出了,不必要继续枚举了 } } cout<<ans1<<" "<<ans2<<" "<<ans3; }
100分代码:
因为sum单调递增。
所以考虑枚举i,再二分确定j
时间复杂度:O(nlogn)

浙公网安备 33010602011771号