题目来源:PAT (Advanced Level) Practice
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
word:
one by one 一个接一个,逐个的 exact 准确的 minimum 最小的,最低的
sufficient 足够的 guarantee 保证,担保
思路:
1. 本题要求从给定的n个数找出 i 和 j 使得从第i个数到第j个数的和刚好等于m,并输出所有满足的i、j对;若没有一组i、j对满足要求则输出从i到j的和大于m最小的数所对应的i、j对(所有i、j对);
2. 使用滑动窗口来来寻找满足要求的i、j对,其中i代表窗口的左端,j代表窗口的右端,t 代表窗口内元素的和,初始为a[1] ,即窗口1-1;
a. 当窗口内的和 t 小于m时,窗口右端向右移动,然后更新窗口内元素和 t ;
b. 当窗口内的和 t 等于m时,输出当前的i、j对且窗口右端向右移动和标记flag=true,更新t;
c. 当窗口内的和 t 大于m时,窗口左端向右移动并且判断当前窗口内值的和是否在当前为大于m的最小值 mi,若是则加入队列中并且删除队列中大于此值的i、j对;然后更新 mi 和 t;
3. 当flag==false时表示没有1个i、j对间的元素和等于m,所以输出队列中的所有元素;
4. 本题在提交时偶尔可能会出现超时现象,但是没有关系,再次提交即可;
//PAT ad 1044 Shopping in Mars
#include <iostream>
using namespace std;
#define N 100005
#include <deque>
deque<pair<int,string> > de; //用于保存没有结果时的最小结果
void op_queue(int i,int j,int t) //操作队列,将和为t的"i-j"加入队列,并且删除大于t的"i-j"
{
de.push_back({t,to_string(i)+"-"+to_string(j)});
while(de.front().first>t)
de.pop_front();
}
int main()
{
int n,m,a[N],i,j;
cin>>n>>m;
for(i=1;i<=n;i++) //输入
cin>>a[i];
bool flag=false; //标记是否有解
int mi=999999999;
int t=a[1]; //t表示i到j的和(窗口内元素的和),初始为1到1,即a[1]
for(i=1,j=1;i<=n&&j<=n;) //设置滑动窗口的两个指针i(窗口左端)和j(窗口右端)
{
if(t>m) //若窗口元素的和大于m
{
if(t<=mi)
{
mi=t; //更新最小值
op_queue(i,j,t); //操作队列,用于在无解的情况下输出最小值
}
t-=a[i]; i++; //窗口左端右移,t更新
}
if(t==m)
{
cout<<i<<"-"<<j<<endl; //输出解
flag=true; //标记有解
t-=a[i]; i++; //窗口左端右移,t更新
}
if(t<m) //若窗口元素的和小于m
{
j++; t+=a[j]; //窗口右端右移,t更新
}
}
if(flag==false) //无解情况时输出队列
{
while(!de.empty())
{
string s=de.front().second;
de.pop_front();
cout<<s<<endl;
}
}
return 0;
}