「CF10E」Greedy Change

题目解析

特殊说明

  • 这篇博客是对于 论文 + 题解 的详细解释。
  • 贪心做法是每次取能取货币中价值最大的货币。
  • 每个引理下面都是证明。

定义 2 2 2 个系统(定义:一个序列的表示方法) C , V C, V C,V
C = ( c 1 , c 2 , . . .   , c n ) C = (c_1, c_2, ... \ , c_n) C=(c1,c2,... ,cn)(这是题目给出的货币系统, c i = a i c_i = a_i ci=ai,即 c i > c i + 1 c_i > c_{i+1} ci>ci+1)。
V = ( v 1 , v 2 , . . .   , v n ) V = (v_1, v_2, ... \ , v_n) V=(v1,v2,... ,vn)(这是对于某一个价值 W W W 的一种构造方案,其中 v i v_i vi 表示使用价值为 c i c_i ci 的货币的数量)。
定义 V = c 1 × v 1 + c 2 × v 2 , . . .   , c n ∗ v n = C ∗ V V = c_1 \times v_1 + c_2 \times v_2, ... \ , c_n * v_n = C * V V=c1×v1+c2×v2,... ,cnvn=CV
G ( W ) G(W) G(W) 表示对于价值 W W W字典序最大贪心 构造方案中(在计算中表示需要的货币数,下标表示第 i i i 个货币使用的数量,有时简写成 G G G)。
M ( W ) M(W) M(W) 表示对于价值 W W W字典序最大最优 构造方案中(在计算中表示需要的货币数,下标表示第 i i i 个货币使用的数量,有时简写成 M M M)。

引理 0

  • G ( W ) G(W) G(W) 的字典序一定 大于等于 M ( W ) M(W) M(W)
  • W W W 越小, G ( W ) G(W) G(W) 的字典序也越小。

因为贪心每次都是取最大的货币,越大的货币越靠前,贪心取的货币一定是达到了上限的,最优方案是不可能超过它的,第二个同理。

引理 1

  • W W W 的贪心构造方案为 V W = ( v 1 , v 2 , . . .   , v n ) V_W = (v_1, v_2, ... \ , v_n) VW=(v1,v2,... ,vn),并记其中取的一个货币为 c i c_i ci
  • 一定有结论:贪心构造方案 V W − c i = ( v 1 , v 2 , . . .   , v i − 1 , . . .   , v n ) V_{W - c_i} = (v_1, v_2, ... \ , v_i - 1, ... \ , v_n) VWci=(v1,v2,... ,vi1,... ,vn)(少取了 1 1 1 c i c_i ci), G ( W ) = G ( W − c i ) + 1 G(W) = G(W - c_i) + 1 G(W)=G(Wci)+1

证明前者:设 W W W 贪心取完 c 1 ∼ i − 1 c_{1 \sim i-1} c1i1 剩下的值为 X X X,取走的总价值为 Y Y Y,所以 W = Y + X W = Y + X W=Y+X(因为能取走 c i c_i ci,所以 X ≥ c i X \geq c_i Xci),所以 W − c i = Y + X − c i W - c_i = Y + X - c_i Wci=Y+Xci Y Y Y 的贪心方案肯定是相同的, X X X X − c i X - c_i Xci 又必须满足每次取最大(贪心),所以只能少取一个 c i c_i ci

证明后者: G ( W ) G(W) G(W) G ( W − c i ) G(W - c_i) G(Wci) 只多取了 1 1 1 c i c_i ci,所以 G ( W ) = G ( W − c i ) + 1 G(W) = G(W - c_i) + 1 G(W)=G(Wci)+1

  • 也可以证明最优构造方案也是如此(也满足前者和后者)

证明后者( M ( W ) = M ( W − c i ) + 1 M(W) = M(W - c_i) + 1 M(W)=M(Wci)+1),因为 M ( W − c i ) M(W - c_i) M(Wci) 也是一种最优方案,多了 1 1 1 c i c_i ci,最少 + 1 +1 +1 M ( W ) M(W) M(W) 也是一种最优方案,所以 M ( W ) = M ( W − c i ) + 1 M(W) = M(W - c_i) + 1 M(W)=M(Wci)+1

证明了后者,前者就显然了,因为字典序最大,所以只能少取 1 1 1 c i c_i ci,否则 M ( W ) M(W) M(W) W ( W − c i ) W(W - c_i) W(Wci) 都不是字典序最大的最优方案。

引理 2

  • G i ≠ 0 G_i \neq 0 Gi=0,则 M i = 0 M_i = 0 Mi=0
  • M i ≠ 0 M_i \neq 0 Mi=0,则 G i = 0 G_i = 0 Gi=0

W W W 是最小的反例(即使得 G ( W ) > M ( W ) G(W) > M(W) G(W)>M(W) 的最小 W W W)。
所以有 G ( W − c i ) = M ( W − c i ) G(W - c_i) = M(W - c_i) G(Wci)=M(Wci),否则 W − c i W - c_i Wci 会是更小的反例
也可以证明构造方案也是相同的,因为要满足字典序最大。

  • G ( W − c i ) = M ( W − c i ) G(W - c_i) = M(W - c_i) G(Wci)=M(Wci)

反证法,如果不满足,即存在 G i > 0 G_i > 0 Gi>0 M i > 0 M_i > 0 Mi>0
则可以同时少取 1 1 1 c i c_i ci,货币数同时 − 1 -1 1,大小关系不会改变,这样 W − c i W - c_i Wci 会是更小的反例,所以一定满足。

引理 3

  • G ( W − c j ) G(W - c_j) G(Wcj) M ( W ) M(W) M(W) 的前 i − 1 i - 1 i1 位相同(都为 0 0 0)。
  • W − c j < c i − 1 W - c_j < c_{i-1} Wcj<ci1

i i i j j j 分别满足 c 1 ∼ i − 1 = 0 , c i ≠ 0 c_{1 \sim i-1} = 0, c_i \neq 0 c1i1=0,ci=0 c j ≠ 0 , c j + 1 ∼ n = 0 c_j \neq 0, c_{j+1 \sim n} = 0 cj=0,cj+1n=0
因为 W W W 是最小的反例,所以 G ( W − c j ) = M ( W − c j ) G(W - c_j) = M(W - c_j) G(Wcj)=M(Wcj)(引理 2 2 2),而 M ( W − c j ) M(W - c_j) M(Wcj) M ( W ) M(W) M(W) 少取了一次 c j c_j cj,只会影响到 v j v_j vj,所以 M ( W − c j ) M(W - c_j) M(Wcj) M ( W ) M(W) M(W) 的前 i − 1 i - 1 i1 位相同(都为 0 0 0),所以 G ( W − c j ) G(W - c_j) G(Wcj) M ( W ) M(W) M(W) 的前 i − 1 i - 1 i1 位相同(都为 0 0 0)。
因为贪心是每次取最大的,又要满足 c 1 ∼ i − 1 c_{1 \sim i-1} c1i1 不取,所以 W − c j < c i − 1 W - c_j < c_{i-1} Wcj<ci1

引理 4

  • G ( W ) G(W) G(W) 1 ∼ i − 1 1 \sim i-1 1i1 上,一定有非零位。
  • W ≥ c i − 1 W \geq c_{i-1} Wci1

反证法,假设 G ( W ) G(W) G(W) 1 ∼ i − 1 1 \sim i-1 1i1 上全是零,又因为 M i ≠ 0 M_i \neq 0 Mi=0,由 引理 2 可知 G i = 0 G_i = 0 Gi=0,所以 G G G 的字典序 小于 M M M 的字典序,不满足 引理 0,假设不成立。

因为 G ( W ) G(W) G(W) 1 ∼ i − 1 1 \sim i-1 1i1 上有非零位,就是至少在前面取一个货币,所以 W ≥ c i − 1 W \geq c_{i-1} Wci1

分析

  • 特殊说明:以下比较均为字典序比较。

根据 引理 3,因为 W , c i − 1 W, c_{i-1} W,ci1 都是整数,所以有 W − c j ≤ c i − 1 − 1 W - c_j \leq c_{i-1} - 1 Wcjci11,即 M ( W − c j ) = G ( W − c j ) ≤ G ( c i − 1 − 1 ) M(W - c_j) = G(W - c_j) \leq G(c_{i-1} - 1) M(Wcj)=G(Wcj)G(ci11)(结合 引理 0, 2)。

根据 引理 4,有 W > c i − 1 − 1 W > c_{i-1} - 1 W>ci11,所以 W − c i ≤ c i − 1 − 1 − c i W - c_i \leq c_{i-1} - 1 - c_i Wcici11ci,所以有 M ( W − c i ) = G ( W − c i ) > G ( c i − 1 − 1 − c i ) M(W - c_i) = G(W - c_i) > G(c_{i-1} - 1 - c_i) M(Wci)=G(Wci)>G(ci11ci),同时多取一个 c i c_i ci,结合 引理 1,有 M ( W ) > G ( c i − 1 − 1 ) M(W) > G(c_{i-1} - 1) M(W)>G(ci11)

结合上面 2 2 2 个,有 M ( W − c j ) ≤ G ( c i − 1 − 1 ) < M ( W ) M(W - c_j) \leq G(c_{i-1} - 1) < M(W) M(Wcj)G(ci11)<M(W)
M ( W ) → M ( W − c j ) M(W) \to M(W - c_j) M(W)M(Wcj) 只是少取了 1 1 1 c j c_j cj,字典序大小却发生了改变,因此 M ( W ) M(W) M(W) G ( c i − 1 − 1 ) G(c_{i-1} - 1) G(ci11) 的前 j − 1 j - 1 j1 位是一样的,不然第 j j j 位不可能影响到字典序大小关系。
又因为 j j j 的定义(引理 3 中)保证 c j + 1 ∼ n = 0 c_{j+1 \sim n} = 0 cj+1n=0,要想从 > > > 变成 ≤ \leq ,又只减少了 1 1 1 次,只可能 M ( W ) M(W) M(W) 的第 j j j 位比 G ( c i − 1 − 1 ) G(c_{i-1} - 1) G(ci11) 的第 j j j 位大 1 1 1

我们可以枚举 i , j i, j i,j,为了方便求出 M ( W ) M(W) M(W) 的每一位的值,可以把 G ( c i − 1 − 1 ) G(c_{i-1} - 1) G(ci11) v j + 1 ∼ n v_{j+1 \sim n} vj+1n 全部去掉,再在第 j j j + 1 +1 +1,就可以求出 W W W 的最优方案,进而求出每一个可能的反例 W W W,再对所有可能的 W W W 取一个 m i n \mathrm{min} min 即可。

需要注意的是, M ( W ) M(W) M(W) 的第 1 1 1 位一定是零。

  • 如果 G 1 ≠ 0 G_1 \neq 0 G1=0引理 2 M 1 = 0 M_1 = 0 M1=0
  • 如果 G 1 = 0 G_1 = 0 G1=0,连贪心都不能取到 c 1 c_1 c1,最优方案也肯定取不到。

所以 i i i 从第 2 2 2 位枚举即可。

枚举 i , j i, j i,j O ( n 2 ) O(n^2) O(n2),求出 W W W 、贪心方案 和 最优方案 O ( n ) O(n) O(n)
总的时间复杂度是 O ( n 3 ) O(n^3) O(n3),而 1 ≤ n ≤ 400 1 \leq n \leq 400 1n400,可以 A C AC AC

代码

#include <cstdio>

int Max(int u, int v) { return (u > v) ? u : v; }
int Min(int u, int v) { return (u < v) ? u : v; }

int rint()
{
	int x = 0, fx = 1; char c = getchar();
	while (c < '0' || c > '9') { fx ^= (c == '-' ? 1 : 0); c = getchar(); }
	while ('0' <= c && c <= '9') { x = (x << 3) + (x << 1) + (c ^ 48); c = getchar(); }
	if (!fx) return -x;
	return x;
}

const int MAX_n = 400;

int n, res = 2e9;
int v[MAX_n + 5];

int main()
{
	n = rint();
	for (int i = 1; i <= n; i++)
		v[i] = rint();
	bool ok = false;
	for (int i = 2; i <= n; i++)
	{
		for (int j = i; j <= n; j++)
		{
			int	sum = 0, dp = 0, now = v[i - 1] - 1; // now = W
			for (int k = 1; k <= j; k++)
				sum += now / v[k], now %= v[k]; // 求出 G(Ci - 1)
			int temp = now = v[i - 1] - 1 - now + v[j]; // 去掉第 j 位后面的, 并在第 j 位上 +1 
			for (int k = i; k <= j; k++)
				dp += now / v[k], now %= v[k]; // 最优方案的货币数 M(W) 
			sum = 0; now = temp;
			for (int k = 1; k <= n; k++)
				sum += now / v[k], now %= v[k]; // 贪心需要的货币数 G(W) 
			if (dp < sum) res = Min(res, temp), ok = true; // 和一个可能的值比最小, 并打上标记 
		}
	}
	printf("%d\n", ok ? res : -1);
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值