题目链接
一开始是用的简单模拟的方法做的,有两个测试点超时。于是把cin、cout改为了scanf、printf,可是仍然超时。主要是套了两层循环,时间复杂度为O(n^2)。
看了柳神代码,说要用二分法,于是我又想了想。可是还是每次把求sum的工作放在了函数里面,时间复杂度还是O(n^2)。然后才想到可以在输入时求从第一个数累计求和到当前的数,保存在数组中,这样方便于求子串的和。
用二分法的话这道题的时间复杂度应该是O(nlogn),快了很多。
AC代码
#include<iostream>
#include<cstring>
using namespace std;
int sum[100005], an[100005];
int min = 999999999;
int solve(int left, int right,int& m) {
int mid,L=left;
while (left < right) {
mid = (left + right) / 2;
if (sum[mid]-sum[L-1]>=m) right = mid;
else left = mid + 1;
}
return left;
}
int main() {
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
int t;scanf("%d", &t);
sum[i] = sum[i - 1] + t;
}
int num = 0;
for (int i = 1; i <= n; i++) {
int j=solve(i, n, m);
int temsum = sum[j] - sum[i - 1];
if (temsum >= m) { //由于二分法可能找到的只是一个假定的位置,即此题中j不存在时也会返回j=i;
if (temsum > min) continue;
if (temsum < min) {
num = 0; min = temsum;
}
an[num++] = i; an[num++] = j;
}
}
for (int i = 0; i < num; i += 2) {
printf("%d-%d\n", an[i], an[i + 1]);
}
return 0;
}
来源:CSDN
作者:正在拼命学习的大学狗
链接:https://blog.csdn.net/weixin_43590232/article/details/104087590