Shopping in Mars
1.思路:
1)因为是求数列i到j的和,所以用一个sum[i]数列表示前i
个数相加,这样当求i到j的和,只用用sum[j]-sum[i-1]。注意这里是sum[i-1],因为sum[i-1]被减掉了,不算在和里。
2)因为当存在给定的和时,要给出i,j,如果不存在,则要给出最小的大于给定的和的i,j。所以先找出第一个大于给定数的j,然后看看sum[j-1]-sum[i-1]与给定数是否相等,否则就代表找到的sum[j]减去sum[i-1]大于给定数。
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 100010;
int nearS = 1000000010;
int sum[maxn], m;
int upper_bound(int L, int R, int x)
{
int left = L, right = R;
while(left < right)
{
int mid = (left + right)/2;
if(sum[mid] > x)
right = mid;
else
left = mid+1;
}
return left;
}
int main()
{
int n;
scanf("%d%d", &n, &m);
sum[0] = 0;
for(int i = 1; i <= n; i++)
{
scanf("%d", &sum[i]);
sum[i] += sum[i-1];
}
for(int i = 1; i <= n; i++)
{
int j = upper_bound(i, n+1, sum[i-1]+m);//这里R为n+1是因为数列中可能没有大于m的数,这样下标自然为n+1
if(sum[j-1]-sum[i-1] == m)
{
nearS = m;
break;
}
else if(j <= n && sum[j]-sum[i-1] < nearS)
{
nearS = sum[j]-sum[i-1];//找出最小值
}
}
for(int i = 1; i <= n; i++)
{
int j = upper_bound(i, n+1, sum[i-1]+nearS);
if(sum[j-1]-sum[i-1] == nearS)
printf("%d-%d\n", i, j-1);
}
}
2.二分法
这里用到了二分法。通常找第一个满足条件的二分法模板为:
例如:找到第一个大于给定数的数组下标。
int binarySearch(int L, int R, int x)
{
int left = L, right = R;
while(left < right)
{
int mid = (left + right)/2;
if(sum[mid] > x)//满足某个条件的时候
right = mid;//这里是因为mid上的那个数也有可能大于x
else
left = mid+1;
}
return left;
}
还有在给定数列中查找某个数:
int binarySearch(int L, int R, int x)
{
int left = L, right = R;
while(left <= right)
{
int mid = (left + right)/2;
if(sum[mid] == x)
return mid;
else if(sum[mid] > x)
right = mid-1;
else
left = mid+1;
}
return -1;//找不到
}
这里用left <= right是因为当找不到这个数的时候,left就已经大于right了。而上面用left<right是因为要找到第一个大于给定数的下标就已经假设这个数存在,也就是left=right的时候了。
上面都是在【left,right】闭区间内找,当区间为左开右闭的时候(left,right】则不一样。
int binarySearch(int L, int R, int x)
{
int left = L, right = R;
while(left+1 < right)
{
int mid = (left + right)/2;
if(sum[mid] > x)
right = mid;
else
left = mid;
}
return right;
}