「JSOI2010」找零钱的洁癖
传送门
个人感觉很鬼的一道题。。。
首先我们观察到不同的数最多 \(50\) 个,于是考虑爆搜。
但是这样显然不太对啊,状态数太多了。
然后便出现了玄学操作:
\(\text{BFS}\) 的过程中,如果队列中的元素太多了(具体多少我也搞不清)就不搜了,相当于卡时。
但这样又可能会WA,然后就贪心一下就好了???我反正是不知道为什么可以
可以看这篇博客
参考代码:
#include <algorithm>
#include <cstdio>
#include <queue>
#include <map>
#define rg register
#define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w", stdout)
using namespace std;
const int _ = 1000002;
int aim, n, a[_], ans, now;
map < int, bool > M;
queue < pair < int, int > > Q;
int main() {
#ifndef ONLINE_JUDGE
file("cpp");
#endif
scanf("%d", &aim);
while (scanf("%d", &a[++n]) != EOF) ; --n;
ans = 0x3f3f3f3f;
sort(a + 1, a + n + 1);
Q.push(make_pair(0, 0)), M[0] = 1;
while (!Q.empty()) {
pair < int, int > x = Q.front(); Q.pop();
if (x.first == aim) { ans = x.second; break ; }
for (rg int xx, i = 1; i <= n; ++i) {
if (x.first < aim && !M[xx = x.first + a[i]]) M[xx] = 1, Q.push(make_pair(xx, x.second + 1));
if (x.first > aim && !M[xx = x.first - a[i]]) M[xx] = 1, Q.push(make_pair(xx, x.second + 1));
}
if (Q.size() > 1000000) break ;
}
if (ans != 0x3f3f3f3f) { printf("%d\n", ans); return 0; }
ans = 0, now = aim;
for (rg int i = n; i >= 1; --i) {
if (a[i] == 0) continue ;
ans += now / a[i];
now -= now / a[i] * a[i];
}
printf("%d\n", ans);
return 0;
}