【LOJ2951】「NOIP2018」货币系统

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39972971/article/details/84983050

【题目链接】

【思路要点】

  • 首先考虑货币系统中最小的面值 x x x x 一定在最小化的货币系统中出现了,并且一定没有比 x x 更小的面值在最小化的货币系统中出现。
  • 仅包含 x x 的当前货币系统能够表示出的面额一定是原有货币系统能表示出的一个子集,考虑在原有货币系统能表示出的面额中选取最小的、当前货币系统不能表示出的面额 y y y y 一定是在原有货币系统中单独作为一种面值出现的。
  • 那么 y y 一定在最小化的货币系统中出现了,并且一定没有除 x x 以外比 y y 更小的面值在最小化的货币系统中出现,这样形成的当前货币系统能够表示出的面额一定也是原有货币系统能表示出的一个子集。
  • 综上所述,最小化的货币系统的面值一定是原有货币系统的面值的一个子集,并且不能被更小的面值表示出来的面值恰好构成了最小化的货币系统。
  • 时间复杂度 O ( T N M a x { A i } ) O(T*N*Max\{A_i\})

【代码】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 105;
const int MAXA = 25005;
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char ch = getchar();
	for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -f;
	for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
	x *= f;
}
bool dp[MAXA];
int n, a[MAXN];
int main() {
	freopen("money.in", "r", stdin);
	freopen("money.out", "w", stdout);
	int T; read(T);
	while (T--) {
		read(n);
		int Max = 0;
		for (int i = 1; i <= n; i++) {
			read(a[i]);
			Max = max(a[i], Max);
		}
		sort(a + 1, a + n + 1);
		memset(dp, false, sizeof(dp));
		dp[0] = true;
		int ans = 0;
		for (int i = 1; i <= n; i++)
			if (!dp[a[i]]) {
				ans++;
				for (int j = a[i]; j <= Max; j++)
					dp[j] |= dp[j - a[i]];
			}
		printf("%d\n", ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39972971/article/details/84983050