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 (≤105), the total number of diamonds on the chain, and M (≤108), the amount that the customer has to pay. Then the next line contains N positive numbers D1⋯DN (Di≤103 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
题目大意
这题就是给出一个数字序列,然后给出一个数值m,要求找出所有满足数字之和等于m的子序列的头尾位置,如果没有满足条件的子序列,则找出所有满足数字之和超过m的最小数字之和的子序列。
个人思路
这题我是设定了一个n位的数组v_sum[],v_sum[i]表示从序列1到序列i的数字之和。然后进行n次二分查找,每次查找都以当前位置为序列头,查找是否存在满足条件的子序列尾。如果还没有满足条件的子序列出现,则将第一个满足子序列数字之和超过m的序列尾存入一个vector。最后判断是否有出现满足条件的子序列,如果没有出现过,则将vector中的记录排序,然后输出。
实现代码
#include <cstdio>
#include <algorithm>
#include <vector>
#include <iostream>
#define ll long long
using namespace std;
const int maxn = 100005;
int v_sum[maxn] = {0}, n, m;
struct node {
int begin, end, data;
};
bool cmp(node a, node b) {
if (a.data != b.data) return a.data < b.data;
else return a.begin < b.begin;
}
bool binary_search(int begin, int &pos, int &ans) {
int left = begin, right = n;
while (left < right) {
int mid = (left + right) / 2;
if (v_sum[mid]-v_sum[begin-1] >= m) right = mid;
else left = mid + 1;
}
pos = left;
ans = v_sum[left]-v_sum[begin-1];
if (ans == m) return true;
return false;
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i ++) {
int tmp;
cin >> tmp;
v_sum[i] = v_sum[i-1] + tmp;
}
vector<node> recs;
bool flag = false;
for (int i = 1; i <= n; i ++) {
int ans, pos;
if (binary_search(i, pos, ans)) {
cout << i << "-" << pos << endl;
flag = true;
}
else if (!flag && ans > m){
node tmp = {i, pos, ans};
recs.push_back(tmp);
}
}
if (!flag) {
sort(recs.begin(), recs.end(), cmp);
for (int i = 0; i < recs.size(); i ++) {
if (recs[i].data == recs[0].data)
cout << recs[i].begin << "-" << recs[i].end << endl;
}
}
return 0;
}
总结
学习不息,继续加油