Codeforces 1620D Exact Change 题解 [ 绿 ] [ 枚举 ] [ 贪心 ] [ 分类讨论 ]
Exact Change:有点幽默的诈骗题。
观察一下性质,不难发现我们选择的 \(1,2\) 最多不超过 \(2\) 个,因为如果存在一个数选了 \(3\) 个 \(1,2\),那么我们可以直接用 \(1\) 个 \(3\) 或者 \(2\) 个 \(3\) 代替,这样一定更优。
接下来看似是一个很复杂的分类讨论,但是你发现我们学的是 OI 不是 MO,所以可以暴力枚举 \(1,2\) 选了多少个!然后 check 一下这个方案是否合法以及最小要选多少个 \(3\) 即可。而对于求出每个数最少要多少个 \(3\),也是枚举这个数用了多少个 \(1,2\) 即可。
时间复杂度 \(O(B\times \sum n)\)。我的代码中 \(B = 3^4\),实际可能有 \(B\) 更小的做法但是显然没有这种做法简洁。
#include <bits/stdc++.h>
#define fi first
#define se second
#define eb(x) emplace_back(x)
#define pb(x) push_back(x)
#define lc(x) (tr[x].ls)
#define rc(x) (tr[x].rs)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
using pi = pair<int, int>;
const int N = 105, inf = 0x3f3f3f3f;
int n, a[N], num3, num1, num2, ans = inf;
void work()
{
int res = num1 + num2;
num3 = 0;
for(int i = 1; i <= n; i++)
{
int tmp = inf;
for(int use1 = 0; use1 <= num1; use1++)
{
for(int use2 = 0; use2 <= num2; use2++)
{
int lst = a[i] - use1 - 2 * use2;
if(lst < 0 || (lst % 3)) continue;
tmp = min(tmp, lst / 3);
}
}
num3 = max(num3, tmp);
}
res += num3;
ans = min(ans, res);
}
void solve()
{
cin >> n;
num3 = num2 = num1 = 0;
ans = inf;
for(int i = 1; i <= n; i++)
cin >> a[i];
for(num1 = 0; num1 <= 2; num1++)
for(num2 = 0; num2 <= 2; num2++)
work();
cout << ans << "\n";
}
int main()
{
//freopen("sample.in", "r", stdin);
//freopen("sample.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while(t--) solve();
return 0;
}

浙公网安备 33010602011771号