链接:https://ac.nowcoder.com/acm/contest/4743/C
来源:牛客网
题目描述:
牛牛有x件材料a和y件材料b,用2件材料a和3件材料b可以合成一件装备,用4件材料a和1件材料b也可以合成一件装备。牛牛想要最大化合成的装备的数量,于是牛牛找来了你帮忙。
输入描述:
输入包含t组数据
第一行一个整数t
接下来t行每行两个整数x,y
输出描述:
每组数据输出一行一个整数表示答案。
朴素做法:
发现 三件甲和一件乙,共花费10件x, 10件b,所以可以通过这个去凑,最后朴素枚举当x、y不够10件的情况
#include <bits/stdc++.h> using namespace std; const int maxn = 1e5 + 5; int a, b, t; int main() { scanf("%d", &t); while (t--) { scanf("%d%d", &a, &b); int ansa = 0, ansb = 0; if (a >= b) { int t = min(b, (a - b) / 3); b -= t, a -= t << 2; ansb = t + b / 10, ansa = b / 10 * 3; a -= b / 10 * 10, b %= 10; } else { int t = min(a >> 1, b - a); b -= 3 * t, a -= t << 1; ansb = a / 10, ansa = t + a / 10 * 3; b -= (a / 10) * 10, a %= 10; } if (a >= 4 && b > 0) { int t = min(a >> 2, b); ansb += t, a -= t << 2, b -= t; } if (a >= 2 && b >= 3) { int t = min(a >> 1, b / 3); ansa += t, a -= t << 1, b -= t * 3; } if (b == 0) while (ansa && a >= 6) { --ansa, a += 2, b += 3; int t = min(a >> 2, b); ansb += t, a -= t << 2, b -= t; } else if (b) while (ansb && b >= 5) { --ansb, b += 1, a += 4; int t = min(a >> 1, b / 3); ansa += t, a -= t << 1, b -= t * 3; } printf("%d", ansa + ansb); if (t) puts(""); } return 0; }
三分做法:
假设做n件甲,那么做$min(frac{x - 2 * n}{4},y - 3 * n)$件乙
总件数$all = n + min(frac{x - 2 * n}{4},y - 3 * n)$,求all的最大值
一般的就是把n枚举,但是从题目x,y<=1e9
n=[0,min(x/2,y/3)]——即完全不做甲 ->完全做甲,时间复杂度是1e9/2
所以我们要用三分缩小n的范围,然后在范围内枚举n
把all看出是关于自变量n的函数,$all=n+min(frac{x - 2 * n}{4},y - 3 * n)$,
三分用之前一定要验证函数是$wedge$或$vee$或或单增或单减的函数,即h(x)'在范围内最多一个零点
然而想一下,x、y差不多的时候($wedge$), x远远大于y的时候(单增),y远远大于x的时候(单减)
每次看两个三分之一点哪个更小,更小的更新为边界
#include <bits/stdc++.h> using namespace std; const int maxn = 1e5 + 5; int a, b, t; int is(int n) { return n + min((a - 2 * n) >> 2, b - 3 * n); } int main() { scanf("%d", &t); for (int i=0;i<t;i++) { scanf("%d%d", &a, &b); int l = 0, r = min(a / 2, b / 3); while (r - l > 3) { int m1 = l + (r - l) / 3, m2 = r - (r - l) / 3; if (is(m1) > is(m2)) r = m2; else l = m1; } int ans = 0; while (l <= r) ans = max(ans, is(l++)); printf("%d ", ans); } return 0; }