Solution - P5228 [AHOI2013] 找硬币

什么啊。


简单 DP 题。注意到把 \(k\) 个面值为 \(n\) 的硬币替换为面值为 \(nk\) 的硬币是没有任何代价的,于是尽量换即可。

然后直接做就行了。复杂度 \(\mathrm O(nm + m \log m)\),其中 \(m\) 为值域。其实如果卡一卡可以做到 \(\mathrm O(n\sqrt m \log m + m \log m)\)

#include <bits/stdc++.h>
#define llong long long 
#define N 100005
using namespace std;

#define bs (1<<20)
char buf[bs], *p1, *p2;
#define gc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,bs,stdin),p1==p2)?EOF:*p1++)
template<typename T>
inline void read(T& x){
    x = 0; int w = 1;
    char ch = gc();
    while(ch < '0' || ch > '9'){
        if(ch == '-') w = -w;
        ch = gc();
    }
    while(ch >= '0' && ch <= '9')
        x = (x<<3)+(x<<1)+(ch^48), ch = gc();
    x *= w;
}
template<typename T, typename ...Args>
inline void read(T& x, Args& ...y){
    return read(x), read(y...);
}

int n, m;
int a[N], b[N];
int tmp[N], dp[N];
int ans;

int main(){
    read(n);
    for(int i = 1; i <= n; ++i)
        read(a[i]), m = max(m, a[i]);
    for(int i = 1; i <= n; ++i)
        for(int j = 1; j <= a[i]; ++j)
            tmp[j] += a[i]/j;
    for(int i = 1; i <= m; ++i) dp[i] = 1e9+7;
    dp[1] = tmp[1], ans = 1e9+7;
    for(int i = 1; i <= m; ++i)
        for(int j = 2; i*j <= m; ++j)
            dp[i*j] = min(dp[i*j], dp[i]-tmp[i*j]*(j-1));
    for(int i = 1; i <= m; ++i) ans = min(ans, dp[i]);
    printf("%d", ans);
    return 0;
}

posted @ 2026-03-18 20:34  Hootime  阅读(2)  评论(0)    收藏  举报