见到最大最小化的先考虑二分答案。。那好就二分可以满足的需求个数。
首先可以确定的优化
1. 删掉比最小的需求都小的木板,删掉比最大给定木板还大的需求。
2. 优先满足更大的需求,从最小的木板开始切。
3. 如果有相等的需求,且上一个相等需求i切了j,那么该需求就从j开始切,可以避免重复搜索量。
4. 如果没被浪费的小于需求的总量就不合法。
概括地说就是要考虑初始的不合法情况,搜索的顺序/贪心的角度,重复搜索的情况,以及当前状态的合法性。
一过样例就交了。。。竟然1A好开心。
实测fread的读入优化并没有比直接getchar快。。
读入优化从8ms->4ms。
可惜只在第二页。
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 1001;
#define FOR(i,j,k) for(i=j;i<=k;i++)
int read() {
int s = 0, f = 1; char ch = getchar();
for (; ch < '0' || ch > '9'; ch = getchar()) if (ch == '-') f = -1;
for (; '0' <= ch && ch <= '9'; ch = getchar()) s = s * 10 + ch - '0';
return s * f;
}
int given[N], needs[N], given_num, needs_num, given_sum, needs_sum[N], waste, mid;
int dfs(int g, int n) {
int i;
if (!n) return 1;
if (waste + needs_sum[mid] > given_sum) return 0; // 4
// 2.2
FOR(i,g,given_num) if (given[i] >= needs[n]) {
given[i] -= needs[n];
if (given[i] < needs[1]) waste += given[i];
if (needs[n] == needs[n - 1]) { // 3
if (dfs(i, n - 1)) g = -555;
} else if (dfs(1, n - 1)) g = -555;
if (given[i] < needs[1]) waste -= given[i];
given[i] += needs[n];
if (g == -555) return 1;
}
return 0;
}
int main() {
int tot = 0, i, l, r, ans = 0;
given_num = read();
FOR(i,1,given_num) given[i] = read();
sort(given + 1, given + given_num + 1);
needs_num = read();
FOR(i,1,needs_num) needs[i] = read();
sort(needs + 1, needs + needs_num + 1);
// 1.2
while (given[given_num] < needs[needs_num]) --needs_num;
// 1.1
FOR(i,1,given_num)
if (given[i] >= needs[1]) given[++tot] = given[i];
else waste += given[i]; // 4
given_num = tot; needs_sum[0] = 0; given_sum = 0;
FOR(i,1,given_num) given_sum += given[i];
FOR(i,1,needs_num) needs_sum[i] = needs_sum[i - 1] + needs[i];
l = 1; r = needs_num;
while (l <= r) {
mid = l + r >> 1;
// 2.1
if (!dfs(1, mid)) r = mid - 1;
else l = mid + 1, ans = mid;
}
printf("%d", ans);
return 0;
}
Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 1351 Solved: 592
农夫约翰打算建立一个栅栏将他的牧场给围起来,因此他需要一些特定规格的木材。于是农夫约翰到木材店购买木材。可是木材店老板说他这里只剩下少部分大规格的木板了。不过约翰可以购买这些木板,然后切割成他所需要的规格。而且约翰有一把神奇的锯子,用它来锯木板,不会产生任何损失,也就是说长度为10的木板可以切成长度为8和2的两个木板。你的任务:给你约翰所需要的木板的规格,还有木材店老板能够给出的木材的规格,求约翰最多能够得到多少他所需要的木板。
第一行为整数m(m<= 50)表示木材店老板可以提供多少块木材给约翰。紧跟着m行为老板提供的每一块木板的长度。接下来一行(即第m+2行)为整数n(n <= 1000),表示约翰需要多少木材。接下来n行表示他所需要的每一块木板的长度。木材的规格小于32767。(对于店老板提供的和约翰需要的每块木板,你只能使用一次)。
只有一行,为约翰最多能够得到的符合条件的木板的个数。
4
25 30 40 50
10
15 16 17 18 19 20 21 24 25 30
7
25切出 21 30切出 20 40切出 19、18 50切出 15、16、17