Shopping in Mars is quite a different experience. The Mars people pay by chained diamonds. Each diamond has a value (in Mars dollars M$). When making the payment, the chain can be cut at any position for only once and some of the diamonds are taken off the chain one by one. Once a diamond is off the chain, it cannot be taken back. For example, if we have a chain of 8 diamonds with values M$3, 2, 1, 5, 4, 6, 8, 7, and we must pay M$15. We may have 3 options:
- Cut the chain between 4 and 6, and take off the diamonds from the position 1 to 5 (with values 3+2+1+5+4=15).
- Cut before 5 or after 6, and take off the diamonds from the position 4 to 6 (with values 5+4+6=15).
- Cut before 8, and take off the diamonds from the position 7 to 8 (with values 8+7=15).
Now given the chain of diamond values and the amount that a customer has to pay, you are supposed to list all the paying options for the customer.
If it is impossible to pay the exact amount, you must suggest solutions with minimum lost.
Input Specification:
Each input file contains one test case. For each case, the first line contains 2 numbers: N (≤10510^5105), the total number of diamonds on the chain, and M (≤10810^8108) ), the amount that the customer has to pay. Then the next line contains N positive numbers D1D_1D1 ⋯DND_NDN (DiD_iDi ≤10310^3103 for all i=1,⋯,N) which are the values of the diamonds. All the numbers in a line are separated by a space.
Output Specification:
For each test case, print i-j in a line for each pair of i ≤ j such that Di + … + Dj = M. Note that if there are more than one solution, all the solutions must be printed in increasing order of i.
If there is no solution, output i-j for pairs of i ≤ j such that Di + … + Dj >M with (Di + … + Dj −M) minimized. Again all the solutions must be printed in increasing order of i.
It is guaranteed that the total value of diamonds is sufficient to pay the given amount.
Sample Input 1:
16 15
3 2 1 5 4 6 8 7 16 10 15 11 9 12 14 13
Sample Output 1:
1-5
4-6
7-8
11-11
Sample Input 2:
5 13
2 4 5 7 9
Sample Output 2:
2-4
4-5
题目大意:给定一个数组和一个值K,若数组存在子序列和为K,则输出所有的子序列的起始下标和末尾下标,若不存在则输出子序列和比K大得最少的序列的起始下标和末尾下标。
解题思路:本题主要是需要求出区间和为K的区间,所以需要求出任意区间的区间和,首先想到的就是计算累加数组,有了累加数组就可以在O(1)的时间复杂度内求解任意区间的区间和,但是枚举出所有区间复杂度为O(n2n^2n2),n最大为10510^5105,限时300ms所以很大概率会超时,那怎么办?因为累加数组是递增的,所有可以采用二分查找,这样就可以优化到O(nlognlog_nlogn),这样就AC了。二分查找可以使用lower_bound,也可以自己写,具体见下面的代码。
下面简单介绍下lower_bound、upper_bound和binary_search函数:
| 函数 | 返回类型 | 含义 |
|---|---|---|
| lower_bound(first, last, value) | 迭代器 | first到last之间的第一个大于等于value的元素,不存在则返回last |
| upper_bound(first, last, value) | 迭代器 | first到last之间的第一个大于value的值的元素。不存在则返回last |
| binary_search(first, last, value) | 布尔值 | 若first到last间存在值等于value则返回true否则返回false |
代码:
#include <bits/stdc++.h>
using namespace std;
const int inf = 9999999;
const long int maxn = 1000000;
int my_find(vector<int>& sum, int i, int k){
//使用二分法从sum数组中第i个元素后的第一个大于等于k的元素的下标
int left = i-1, right = sum.size(), mid;
while(left <= right){
mid = (left + right) / 2;
if(sum[mid] > k)
right = mid - 1;
else if(sum[mid] == k)
return mid;
else if(sum[mid] < k)
left = mid + 1;
}
return left;
}
int main(int argc, char const *argv[])
{
int n,m;
cin >> n >> m;
vector<int> num(n), sum(n+1, 0);
for(int i = 0;i < n; i++){
scanf("%d", &num[i]);
sum[i+1] = sum[i] + a[i];
}
vector<long int> ans, min_lost_ans;
int flag = 0;
int min_lost = inf;
for(int i = 1;i <= n; i++){
// 找出sum数组中从i开始,第一个大于m的值的下标,这个i是必须的,否则不能AC
// int j = (int)(lower_bound(sum.begin()+i, sum.end(), k) - sum.begin());
int j = my_find(sum, i, m);
for(;j <= n; j++){
if(sum[j] - sum[i-1] - m > min_lost) break;
if(sum[j] - sum[i-1] == m){
flag = 1;
ans.push_back(i*maxn+j);
}
else if(sum[j] - sum[i-1] > m && sum[j] - sum[i-1] - m == min_lost){
min_lost_ans.push_back(i*maxn+j);
}
else if(sum[j] - sum[i-1] > m && sum[j] - sum[i-1] - m < min_lost){
min_lost = sum[j] - sum[i-1] - m;
min_lost_ans.clear();
min_lost_ans.push_back(i*maxn+j);
}
}
}
if(flag == 1){
for(int i = 0;i < ans.size(); i++){
printf("%ld-%ld\n", ans[i]/maxn, ans[i]%maxn);
}
}
else{
for(int i = 0;i < min_lost_ans.size(); i++){
printf("%ld-%ld\n", min_lost_ans[i]/maxn, min_lost_ans[i]%maxn);
}
}
return 0;
}
本文探讨在火星上一种独特的购物支付方式,使用链式钻石作为货币单位。通过算法寻找最优支付方案,确保顾客能够以最小损失完成交易。文章详细介绍了如何通过二分查找优化区间和的计算,以解决大规模数据下的效率问题。
381

被折叠的 条评论
为什么被折叠?



