题意
给一套货币,保证任意两种货币存在倍数关系且颜色互不相同。已知货币的币值集合,每次可以询问一个金额,给出货币张数最小的表示方案。问最小的询问次数,使得通过已知信息可以对应货币面值和颜色。
分析
最大的面值问一个 \(\inf\) 即可。这时只需要考虑前 \(n-1\) 个面值。
将货币之间的倍数关系看做一个进制关系。每次询问一个金额就是询问一个各个位置进制不同的数。既然面值集合已知,则任何询问我们自己已经知道拆分的结果,可能混淆的只是每次询问个数都相同的不同颜色。这样问题转化为如何通过有限次询问将所有货币在所有轮贡献的集合互不相同。一个细节是全为 \(0\) 的面值无法确定,原因是根本无法知道这个货币的颜色。
这时问题已经与货币面值无关,不妨将货币的进制排序。
假设有两次询问,第一行表示该位置的进制,纵列表示填的数。举例如下:
2 | 2 | 2 | 3 | 3 | 3 | 3 | 3 | 3 |
---|---|---|---|---|---|---|---|---|
0 | 1 | 1 | 0 | 1 | 1 | 2 | 2 | 2 |
1 | 0 | 1 | 2 | 1 | 2 | 0 | 1 | 2 |
注意看第三列,此时的二进制已经没有可用的数字集合。如果再加一个二进制的列就不够了,需要多加一行。可知全为 \(d\) 进制的 \(n\) 种货币可以表示 \(d^{n}-1\) 种不同金额。反过来,\(n\) 货币的系统中,使得集合互不相同的至少询问次数是 \(\lceil \log_d (n+1) \rceil\)。
进制不相同的情况怎么处理?注意到为保证合法,二进制的区间我们只用了 \(01\),而三进制下为了保证最优,同样会在较前的列只用 \(01\),于是二进制和三进制是等价的,只不过我们没有填 \(2\) 而已。
实现上,只有 \(d\) 变化的时候我们才会统计答案,答案取瓶颈的最大值。
void solve() {
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i < n; i++) b[i] = a[i + 1] / a[i];
sort(b + 1, b + n);
for (int i = 1; i < n; i++)
if(b[i] != b[i + 1])
ans = max(ans, lg(b[i], i+1)); // log i+1 base b_i
cout << ans << endl;
}
标签:SRM616,二进制,题解,询问,面值,货币,TopCoder,集合,进制
From: https://www.cnblogs.com/tai-chi/p/18468148