砝码
题目链接:砝码
题解
思路
题目要求尽可能多的带走砝码,那么我们就要从重量最小的开始带。
由题意,任意两个砝码之间都有倍数关系,则可以从砝码中找到最小的重量,我们暂时称之为砝码的重量单位。
其余砝码的重量都可以表示为若干个砝码的重量单位。
对于容器,要带走一个砝码,必须保证其剩余容量大于等于该砝码。根据上文所得,我们可以将容器容量也表示为若干个砝码的重量单位,多余部分将不能带走任何砝码,故可以忽略不计。
联想二进制等进制, 我们将砝码的种类表示成X进制,并将容器容量用X进制表示。
实现
kind数组
:用于存储砝码的种类,以便将容量表示成X进制的数字。
digit数组
:digit[i]
=容器所能容纳的该种砝码的数量。利用上文提到的“砝码的重量单位”,每一个大容器都可以拆分成若干个小容器,即加减法中的借位操作。
在实际计算中,我们遍历经过升序排序后的所有的砝码。对于砝码w[i]
,去寻找该砝码对应的种类在kind数组
中的下标,以对应地寻找digit数组
中的数量digit[i]
,当digit[i]
不为0时,表明当前容量可以存储该砝码;当digit[i]
等于0时,判断是否可以借位,借位后同digit[i]
不为0的情况,不能借位则表明不能存储该砝码,由于砝码重量经过升序排序,故若当前砝码不能存储,则其后的所有砝码也不能存储,此时可直接结束,输出答案(不输出接着判断也行)。
AC代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<string>
#include<queue>
#include<map>
#include<stack>
#include<list>
#include<set>
#include<deque>
#include<vector>
#include<ctime>
using namespace std;
//#pragma GCC optimize(2)
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define ull unsigned long long
#define ll long long
#define rep(i, x, y) for(int i=x;i<=y;i++)
#define mms(x, n) memset(x, n, sizeof(x))
#define mmc(a, b) memcpy(a, b, sizeof(b))
#define INF (0x3f3f3f3f)
#define mod (ull)(1e9+7)
typedef pair<int, int> P;
namespace FastIO {
const int bufsiz = 1 << 22;
char buf[bufsiz];
inline char getch() {
static int tot;
tot++;
if (tot == bufsiz) {
fread(buf, 1, bufsiz, stdin);
tot = 0;
}
return buf[tot];
}
inline int read() {
int x = 0;
char c = getch();
while (!isdigit(c))c = getch();
while (isdigit(c))x = x * 10 + c - '0', c = getch();
return x;
}
}
using FastIO::read;
const int N = 1e5 + 10;
int n, m;
int digit[N];
int cap[N], w[N];
int kind[N], top;
bool check(int pos) {
for (int i = pos + 1; i <= top; i++) {
if (digit[i]) {
digit[i]--;
digit[pos] += kind[i] / kind[pos];
return true;
}
}
return false;
}
int main() {
// freopen("input.txt", "r", stdin);
// freopen("output.txt", "w", stdout);
n = read(), m = read();
rep(i, 1, n) cap[i] = read();
rep(i, 1, m)w[i] = read();
sort(w + 1, w + m + 1);
rep(i, 1, m) if (w[i] != w[i - 1]) kind[++top] = w[i];
rep(i, 1, n) {
for (int j = top; j >= 1; j--) {
digit[j] += cap[i] / kind[j];
cap[i] %= kind[j];
}
}
int ans = 0;
rep(i, 1, m) {
rep(j, 1, top) {
if (w[i] == kind[j]) {
if (digit[j]) {
digit[j]--;
ans++;
} else if (check(j)) {
digit[j]--;
ans++;
}
break;
}
}
}
printf("%d", ans);
return 0;
}