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:
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 ( ≤ 10 5 ) N (≤10^5) N(≤105), the total number of diamonds on the chain, and M ( ≤ 1 0 8 ) M (≤10^8) M(≤108), the amount that the customer has to pay. Then the next line contains N positive numbers D 1 , . . . , D N ( D i ≤ 10 3 , ∀ i = 1 , ⋯ , N ) D_1,...,D_N(D_i≤10^3,\forall i=1,⋯,N) D1,...,DN(Di≤103,∀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 i ≤ j i≤j such that D i + . . . + D j = M Di + ... + Dj = M Di+...+Dj=M. Note that if there are more than one solution, all the solutions must be printed in increasing order of i i i.
If there is no solution, output i − j i-j i−j for pairs of i ≤ j i ≤ j i≤j such that D i + . . . + D j > M D_i + ... + D_j >M Di+...+Dj>M with ( D i + . . . + D j − M ) (D_i + ... + D_j −M) (Di+...+Dj−M) minimized. Again all the solutions must be printed in increasing order of i i 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
题目大意: 给N个连续的钻石,问如何切割,才能够付款M的钻石段,如果没有刚好M的钻石,那么至少也要保证损失最小。
解题思路: 输入的时候直接计算价值总和,这样可以避免重复计算从i到j的累加和。
(1) ∑ i j s u m = d i a m o n d s [ i ] − d i a m o n d s [ j ] \sum_{i}^{j}{sum = diamonds[i] - diamonds[j]} \tag{1} i∑jsum=diamonds[i]−diamonds[j](1)
同时,每一次输入数据i,进行一次判定,设置地位索引low,判断从low到i累加,是否超过了M,如果超过,说明可能存在符合要求的区间,low往前移位,直到找到满足M的区间,然后直接输出,如果不满足,记录最小值点。
注意,每一次输入i,low不必从0开始,i每往后移动一位,low跟着往前移动即可,因为前面的i都已经计算过了,low从零开始只会重复计算。
如果始终找不到M的点,重新从头开始遍历,比较之前记录的最小值点,该点是大于M但是最接近M的点,保证损失最小。输出所有符合该要求的区间。
/*
** @Brief:No.1044 of PAT advanced level.
** @Author:Jason.Lee
** @Date:2018-12-18
** @Solution: https://blog.csdn.net/CV_Jason/article/details/85074263
*/
#include
#include
#define MAX 100001
using namespace std;
int diamonds[MAX];
int main(){
int N,M,input;
while(cin>>N>>M){
int minlost = 99999999;
int low = 0;
bool notFound = true;
fill(diamonds,diamonds+MAX,0);
for(int i=1;i<=N;i++){
cin>>diamonds[i];
diamonds[i]+=diamonds[i-1];
while(diamonds[i] - diamonds[low]>M){
minlost = min(minlost,diamonds[i] - diamonds[low]);
low++;
}
if(diamonds[i] - diamonds[low] == M){
cout<<low+1<<"-"<<i<<endl;
notFound = false;
}
}
if(notFound){
low = 0;
for(int i=1;i<=N;i++){
while(diamonds[i] - diamonds[low]>minlost){
low++;
}
if(diamonds[i] - diamonds[low]==minlost){
cout<<low+1<<"-"<<i<<endl;
}
}
}
}
return 0;
}
还有一种比较常规的做法是用二分查找,因为求和数组是递增的,因此自带升序排列的属性,因此,我们只需要查找两者相减等于M或者最接近M。但这种做法需要同时记录所计算的区间,比起本文的方法,略显笨拙。