PKU 3093 Margaritas on the River Walk

http://acm.pku.edu.cn/JudgeOnline/problem?id=3093

  • DP
  • あかかじめ値段の昇順にソートしておく
  • 安い店から順に辿っていき、買うか買わないかで分岐する
  • 他の店で買えなくなるまで買うという条件を満たすため、自分が買わなかったマリゲータのうち最も安い物を覚えておく
  • いずれも買えない場合は0を出力
//[どこまで見た][最初から連続して使ったのはどこまでか][金額]
static ll dp[32][32][1024];

int main()
{
	int N;
	cin >> N;
	for (int testCase = 1; testCase <= N; ++testCase) {
		int V, D;
		cin >> V >> D;
		vector<int> costs;
		for (int i = 0; i < V; ++i) {
			int cost;
			cin >> cost;
			costs.push_back(cost);
		}
		costs.push_back(10000);
		sort(costs.begin(), costs.end());

		if (costs.front() > D) {
			cout << testCase << " " << 0 << endl;
			continue;
		}

		memset(dp, 0, sizeof(dp));
		dp[0][0][0] = 1;
		for (int v = 0; v < V; ++v) {
			for (int i = 0; i < V; ++i) {
				for (int d = 0; d <= D; ++d) {
					if (!dp[v][i][d]) {
						continue;
					}

					// 買わないで次に行く
					dp[v + 1][i][d] += dp[v][i][d];

					// 買って次に行く
					if (d + costs[v] <= D) {
						if (v == i) {
							// ここまで全て購入した
							dp[v + 1][i + 1][d + costs[v]] += dp[v][i][d];
						} else {
							dp[v + 1][i][d + costs[v]] += dp[v][i][d];
						}
					}
				}
			}
		}

		ll answer = 0;
		for (int d = 0; d <= D; ++d) {
			for (int i = 0; i <= V; ++i) {
				if (dp[V][i][d] && D - d < costs[i]) {
					const ll value = dp[V][i][d];
					answer += value;
				}
			}
		}

		cout << testCase << " " << answer << endl;
	}
}