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;
}
posted @ 2025-09-04 17:27  KS_Fszha  阅读(7)  评论(0)    收藏  举报