1. 程式人生 > >[POI2007]砝碼Odw 貪心

[POI2007]砝碼Odw 貪心

Descripition 給你n個箱子,m個物品,問你最多能裝多少個物品,其中物品滿足任意兩個物品,他們中總有一個是另一個的整數倍。

Sample Input 2 4 13 9 4 12 2 4

Sample Output 3

這道題好神啊。。。 假設物品為{a1,a2,…,an},利用進位制拆分的思想。 對於一個箱子,你可將其拆分成k1a1+k2a2+…+knan這樣的一個式子,即變成一個n元組:{k1,k2,…,kn}。 然後你將每一個箱子箱子的n元組相加,然後從權值較低的物品開始判斷當前位置是否能填,不行你就向高位借一下位什麼的。。。

#include <cstdio>
#include <cstring> #include <algorithm> using namespace std; typedef long long LL; int read() { int s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();} while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar(); return
s * f; } LL s[110000]; int cnt, c[110000]; int a[110000], b[110000], belong[110000]; int main() { int n = read(), m = read(); for(int i = 1; i <= n; i++) a[i] = read(); for(int i = 1; i <= m; i++) b[i] = read(); sort(b + 1, b + m + 1); for(int i = 1; i <= m; i++) { if(b[i] != b[i - 1
]) c[++cnt] = b[i]; belong[i] = cnt; } for(int i = 1; i <= n; i++) { for(int j = cnt; j >= 1; j--) if(a[i] >= c[j]){ int k = a[i] / c[j]; s[j] += k; a[i] -= k * c[j]; } } int ans = 0, S = 0; for(int i = 1; i <= m; i++) { if(s[belong[i]]) ans++, s[belong[i]]--, S++; else { int k = belong[i]; while(k <= cnt && !s[k]) k++; if(k > cnt) break; for(int j = k - 1; j >= belong[i]; j--) { s[j] += c[j + 1] / c[j]; s[j + 1]--; } ans++; s[belong[i]]--; } } printf("%d\n", ans); return 0; }