luoguP2329 [SCOI2005]栅栏
Posted lylyl
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luoguP2329 [SCOI2005]栅栏相关的知识,希望对你有一定的参考价值。
首先我们可以看出一个性质:取小的一定不比取大的劣.显然嘛
于是我们将约翰所需的木板从小到大排序,原材料也按从小到大排序,然后二分一个(mid)表示约翰取几个木板,用搜索(check)一下即可.
几个剪枝:
一.我们可以定义一个全局变量(Waste)表示割下木板后总共浪费的原材料长度.
( herefore) 如果(Waste+sum_{i=1}^{mid}b_i>sum),直接退出,返回(0).
二.对于两个长度相等的所需木板,我们可以记一个(last)表示之前的所需木板找到了第(last)个,( herefore)直接从(last)开始找即可.
三.我们在二分前可以先将总和大于(sum)的删去,即(while (s[r] > sum)--r;)
#include<bits/stdc++.h>
#define il inline
#define rg register
#define gi read<int>
using namespace std;
template<class TT>
il TT read() {
TT o = 0,fl = 1; char ch = getchar();
while (!isdigit(ch) && ch != '-') ch = getchar();
if (ch == '-') fl = -1, ch = getchar();
while (isdigit(ch)) o = o * 10 + ch - '0', ch = getchar();
return fl * o;
}
int n, m, sum, l, r, mid, t, ans, a[55], b[1005], c[55], s[1005];
bool check(int x, int last) {
if (!x) return true;
if (sum < t + s[mid]) return false;
for (int i = last; i <= m; ++i) {
if (c[i] >= b[x]) {
c[i] -= b[x];
if (c[i] < b[1]) t += c[i];
if (b[x] == b[x - 1]) {
if (check(x - 1, last)) return true;
}
else if (check(x - 1, 1)) return true;
if (c[i] < b[1]) t -= c[i];
c[i] += b[x];
}
}
return false;
}
int main() {
m = gi();
for (int i = 1; i <= m; ++i)
a[i] = gi(), sum += a[i];
sort(a + 1, a + m + 1);
n = gi();
for (int i = 1; i <= n; ++i) b[i] = gi();
sort(b + 1, b + n + 1);
for (int i = 1; i <= n; ++i) s[i] = s[i - 1] + b[i];
l = 1, r = n;
while (s[r] > sum) --r;
while (l <= r) {
for (int i = 1; i <= m; ++i) c[i] = a[i];
mid = l + r >> 1, t = 0;
if (check(mid, 1)) ans = mid, l = mid + 1;
else r = mid - 1;
}
printf("%d
", ans);
return 0;
}
以上是关于luoguP2329 [SCOI2005]栅栏的主要内容,如果未能解决你的问题,请参考以下文章
[BZOJ1082][SCOI2005]栅栏 二分+搜索减枝