PAT A1044火星でのショッピング(25ポイント)(質問+コード+詳細なメモ)

火星でのショッピングは、まったく異なる体験です。火星の人々はチェーンダイヤモンドで支払います。各ダイヤモンドには値があります(火星ドルM $)。お支払いの際、チェーンはどこでも一度だけカットでき、一部のダイヤモンドはチェーンから1つずつ外れます。ダイヤモンドがチェーンから外れると、元に戻すことはできません。たとえば、M $ 3、2、1、5、4、6、8、7の値を持つ8つのダイヤモンドのチェーンがある場合、M $ 15を支払う必要があります。3つのオプションがあります。

  1. チェーンを4と6の間で切り、1から5の位置からダイヤモンドを外します(値は3 + 2 + 1 + 5 + 4 = 15)。
  2. 5の前または6の後にカットし、4から6の位置からダイヤモンドを取り出します(値は5 + 4 + 6 = 15)。
  3. 8の前にカットし、7から8の位置からダイヤモンドを外します(値は8 + 7 = 15)。

ひし形の値のチェーンと顧客が支払う必要のある金額を考えると、顧客のすべての支払いオプションをリストすることになっています。

正確な金額を支払うことが不可能な場合は、損失を最小限に抑えた解決策を提案する必要があります。

入力仕様:

各入力ファイルには1つのテストケースが含まれています。いずれの場合も、最初の行には2つの数値が含まれています。N(≤105)はチェーン上のダイヤモンドの総数、M(≤108)は顧客が支払う必要のある金額です。次に、次の行には、ダイヤモンドの値であるN個の正の数値D 1⋯D N(すべてのi = 1、⋯、Nに対してD i≤103)が含まれています。行内のすべての数値はスペースで区切られています。

出力仕様:

テストケースごとに 、D  + ... + D  = Mとなるような ≤の  i-j ペアごとに1行に印刷  し  ます。複数のソリューションがある場合、すべてのソリューションをの昇順で印刷する必要があることに注意してください  ijiji

解がない場合、 (D  + ... + D  −M)が最小化さ れたD  + ... + D > Mとなるような ≤の  i-j ペアの  出力  繰り返しになりますが、すべての解はの昇順で印刷する必要があります  ijijiji

ダイヤモンドの合計金額が指定された金額を支払うのに十分であることが保証されています。

入力例1:

16 15
3 2 1 5 4 6 8 7 16 10 15 11 9 12 14 13

出力例1:

1-5
4-6
7-8
11-11

入力例2:

5 13
2 4 5 7 9

出力例2:

2-4
4-5

//質問の意味は次のとおりです:一連の数値を指定して、シーケンスとすべての連続するサブシーケンスSを見つけます存在しない場合は、Sより大きい最も近いサブシーケンスを見つけます。

//アイデア:2つのステップ:(1)そのようなシーケンスがあるかどうかを判別します(2)条件を満たす条件を出力します

//考える:2つのポイント(または2つのポインター)

//具体的な実装については、詳細についてACコードを参照してください。

#include<cstdio>
#include<iostream>
#include<algorithm>

using namespace std;
int sum[100005];        //sum[i]表示从第1个到第i个之间所有的数字之和,且易知sum数组是严格递增的

int main() {
	int n, S, nearS = 100000005;      //S是题目给出的和,nearS表示最接近S的和,初始化为最大数据1e+8
	cin >> n >> S;                      //读入值
	for (int i = 1; i <= n; i++) {
		cin >> sum[i];              
		sum[i] += sum[i - 1];           //读入时算出sum[i]的值
	}

//找到nearS
	for (int i = 1; i <= n; i++) {
		int j = upper_bound(sum + i, sum + n + 1, S + sum[i - 1]) - sum;   //调用该库函数,找出第一个j使得i和j之间的数字之和大于S
		if (sum[j - 1] - sum[i - 1] == S) {      //由于找到的j是大于,所以分析j - 1,sum[j-1]-sum[i-1]是第i个到第j - 1之间所有数的和
			nearS = S;             //更新最接近S的值为S,这时就可以跳出循了
			break;
		}
		int k = sum[j] - sum[i - 1];    //如果上一步没跳出循环,则说明[i,j-1]之间的数之和小于S,因此直接分析[i, j],这个结果肯定是大于S的
		if (k < nearS && j <= n)         //判断是否更新nearS,后一个条件是因为如果没找到满足条件的j,那么j的下标是n + 1
			nearS = k;
	}

//输出部分, 和上面的循环差不多,只是将S换成了nearS
	for (int i = 1; i <= n; i++) {
		int j = upper_bound(sum + i, sum + n + 1, nearS + sum[i - 1]) S- sum;    
		if (sum[j - 1] - sum[i - 1] == nearp)
			cout << i << "-" << j - 1 << endl;
	}

	return 0; 
}

//最後のステートメント、この質問は神のコードの明確なメモに触発されました。侵害の場合は、削除してください!

//のように見えると、これ良い習慣です。

おすすめ

転載: blog.csdn.net/qq_45472866/article/details/104830658