这题写了好几版,都说超时,看了看书才想到用二分查找。
思路:
1:边输入边累加,得出Sum[i](Sum[0]=0不能忘记),这样Sum[i]-Sum[j]即为i-j数列之和。
2:得出Sum[i]的连续递增的数列之后,遍历Sum[i],对每个Sum[i],用二分法找到>=M的Sum[r],两者相减得i-r数列,用min记录最小值,以及ans记录i,r,最后遍历完以后ans就行
二分法模板:
int l=i+1,r=n;
while (l<r){
int mid = (l+r)/2;
vsum = sum[mid] - sum[i];
if (vsum<x){ //注意这里有没有等号,要看如果sum[mid]刚好是要找的值,比如这里如果写了等号,l和r就比mid大1
l = mid+1;
} else {
r = mid;
}
}
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 100010,INF = 1000000;
int a[maxn],sum[maxn];
int n;
struct Ans{
int a,b;
}ans[maxn];
int search(int x){
int vsum,round,min=INF,t=0; //t为答案的个数
for (int i=0;i<n;i++){ //对每个sum
int l=i+1,r=n;
while (l<r){ //二分
int mid = (l+r)/2;
vsum = sum[mid] - sum[i];
if (vsum<x){
l = mid+1;
} else {
r = mid;
}
}
vsum = sum[r] - sum[i]; //找到sum[r],就得出数列和
round = vsum-x; //得出与M的差值
if (round>=0 && round < min ) { //如果数列和比M大,并且最小,就更新
min = round;
t=0;
ans[t].a = i+1;
ans[t++].b = r;
} else if (round>=0 && round == min){ //相等就增加答案
ans[t].a = i+1;
ans[t++].b = r;
}
}
return t;
}
int main(){
long long m;
scanf("%d%lldd",&n,&m);
sum[0]=0;
for (int i=1;i<=n;i++){
scanf("%d",&a[i]);
sum[i] = sum[i-1] + a[i];
}
int p = search(m);
for (int i=0;i<p;i++){
printf("%d-%d\n",ans[i].a,ans[i].b);
}
return 0;
}