1. 程式人生 > 其它 >【YBTOJ】【Luogu P5020】[NOIP2018 提高組] 貨幣系統

【YBTOJ】【Luogu P5020】[NOIP2018 提高組] 貨幣系統

【YBTOJ】【Luogu P5020】[NOIP2018 提高組] 貨幣系統:

連結:

洛谷

題目大意:

在網友的國度中共有 \(n\) 種不同面額的貨幣,第 \(i\) 種貨幣的面額為 \(a[i]\),你可以假設每一種貨幣都有無窮多張。為了方便,我們把貨幣種數為 \(n\)、面額陣列為 \(a[1..n]\) 的貨幣系統記作 \((n,a)\)

在一個完善的貨幣系統中,每一個非負整數的金額 \(x\) 都應該可以被表示出,即對每一個非負整數 \(x\),都存在 \(n\) 個非負整數 \(t[i]\) 滿足 \(a[i] \times t[i]\) 的和為 \(x\)。然而, 在網友的國度中,貨幣系統可能是不完善的,即可能存在金額 \(x\)

不能被該貨幣系統表示出。例如在貨幣系統 \(n=3\), \(a=[2,5,9]\) 中,金額 \(1,3\) 就無法被表示出來。

兩個貨幣系統 \((n,a)\)\((m,b)\) 是等價的,當且僅當對於任意非負整數 \(x\),它要麼均可以被兩個貨幣系統表出,要麼不能被其中任何一個表出。

現在網友們打算簡化一下貨幣系統。他們希望找到一個貨幣系統 \((m,b)\),滿足 \((m,b)\) 與原來的貨幣系統 \((n,a)\) 等價,且 \(m\) 儘可能的小。他們希望你來協助完成這個艱鉅的任務:找到最小的 \(m\)

題目大意:

\(a\) 中可能有的數會被其它數表示出來,把這些數篩掉就完事了。

程式碼:


inline ll Read()
{
	ll x = 0, f = 1;
	char c = getchar();
	while (c != '-' && (c < '0' || c > '9')) c = getchar();
	if (c == '-') f = -f, c = getchar();
	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
	return x * f;
}

int n, a[N], f[M];

int main()
{
	for (int t = Read(); t--; )
	{
		n = Read();
		memset (f, 0, sizeof (f));
		for (int i = 1; i <= n; i++) 
			a[i] = Read();
		int ans = n;
		sort (a + 1, a + 1 + n);
		f[0] = 1;
		for (int i = 1; i <= n; i++)
		{
			if (f[a[i]]) {ans --; continue;}
			for (int j = a[i]; j <= a[n]; j++)
				f[j] |= f[j - a[i]];
		}
		printf ("%d\n", ans);
	}
	return 0;
}