CF10E Greedy Change


  • 题意:
    CF10E
    有一些大到小排列货币 \(a_{1...n}\),每个可以选无限个,最小化凑出 \(S\) 的货币个数。

找到一个最小的hack贪心大到小选的 \(S\)

  • 结论:

\(G(S)\)\((v_1,v_2,...v_n)\), 为贪心下每个货币选了的个数,实际上求的是满足和为 \(S\)最大字典序

\(M(S)\) 为最优解每个货币选了的个数,实际上求的是个数最少的前提下的最大字典序

如果存在反例 \(w\), 那么 \(M(w) < G(w)\)

  1. \(M(w)\)\(G(w)\) 每位互不相同,可以理解为用零散的小的货币拼出一个完整的大货币,恰好不相交。

  2. \(M(w)\) 的最小和最大非零位为 \(i, j\), \(M(w)\)\(G(c_{i - 1} - 1)\)\(1...j-1\) 为相同,第 \(j\) 位大 1。

所以可以枚举最高位的 \(j\), 这里 \(w\) 就是前 \(1...j\)位 的 \(c_{i - 1} - 1\) 加上一个 \(a_j\)。 利用 \(G(c_{i - 1} - 1) + 1\) 算出 \(M(w)\),再算出 \(G(w)\) 比较。

int n;
cin >> n; 
vector a(n); 
for (ll &i : a) cin >> i; 
ll ans = INF;
for (int i = 1; i < n; i ++) {
        auto G = [=] (int x) {
		int cnt = 0;
	        for (ll i : a) 
		    cnt += x / i, x %= i; 
		return cnt;  
	}; 
	int c = a[i - 1] - 1, now = c; 
	int M = 0;
	for (int j = i; j < n; j ++) {
		M += now / a[j]; 
		now %= a[j];
		ll w = c - now + a[j];  
		if (M + 1 < G(w)) 
		    ans = min(ans, w) ; 
	}
}
if (ans == INF) cout << -1;
else cout << ans;