大意:找和(最小)大于等于给定价格的多个连续区间
不太喜欢晴神宝典上的题解,
所以借鉴了 Jcldcdmf的题解
感谢!
# include <iostream>
# include <vector>
# include <algorithm>
# include <climits>
using namespace std;
const int maxn = 100010;
int N; // 链子上钻石的个数
int Amount; // 要付的价格
int Sums[maxn] = {0}; // accumulate 累计和
int minpay = INT_MAX; // 最少要付的钱,最小为Amount,如果在所有钻石中找不到加和为Amount的,就要多花大于Amount的钱
vector<pair<int, int>> QuJian; // 存放区间
int MYlower_bound(int l, int h, long long x)
{
long long mid;
while(l < h)
{
mid = (l + h) / 2;
if(Sums[mid] >= x)
h = mid;
else
l = mid + 1;
}
return h;
}
// 寻找累计和大于等于amount的区间
void findQuJian(int i)
{
// int j = lower_bound(Sums+i, Sums+N+1, Sums[i]+Amount) - Sums;
int j = MYlower_bound(i, N+1, Sums[i]+Amount);
int differ = Sums[j]-Sums[i];
// cout << i << " " << j << " " << differ << " " << minpay <<endl;
// 第一次循环必定会进入这里更新minpay,如果minpay更新为amount(也就是这次的价差differ等于amount)的话,这里就永远不会再进入
/* differ >= Amount是为了防止溢出边界而进入if中的情况,此外并无作用
(因为如果是输入的数据的话Sums[j]-Sums[i]必然大于等于amount,
如果是溢出边界的数据就会出现负数的情况(因为Sums都初始化为0),所以就是为了避免这种情况) */
if(differ >= Amount && differ < minpay){
minpay = differ;
QuJian.clear(); //
QuJian.push_back({i+1, j});
}
// 如果differ == Amount 的话,会有多种最少的支付方式
// 如果differ == Amount + 多损失的钱x 的话,也会有多种相等的损失钱的情况
//(这就是这里是differ == minpay而不是differ==Amount的原因)
else
if(differ == minpay){
QuJian.push_back({i+1, j});
}
}
int main()
{
scanf("%d %d", &N, &Amount);
for(int i=1;i<=N;++i){
scanf("%d", &Sums[i]);
Sums[i] += Sums[i-1];
}
for(int i=0;i<N;++i)
findQuJian(i);
for(auto i: QuJian)
printf("%d-%d\n", i.first, i.second);
return 0;
}
}