题意: 有a,b,c三种数,有多少种三个数的组合,使得每组数,至少一个a一个b。
思路: 二分是很显然的,但是还可以推公式。比赛的时候写的是二分。赛后看大牛的代码,貌似就3种情况:x,y,(x+y+z)/3。取最小值就可以了。理由的话,就是按种类数足的话,就按人数取,种类数不足的话,就按照种类数取。
但是这样感觉还是不自然(没有严谨的数学推理)。
假设三类数数目分别为x,y,z。令a = min(x, y) ,b = x + y + z - 3 * a。那么,a代表能组成最多多少组,b代表组成a组后剩下的人数。如果b >= 0,很明显可以组成a组,那就输出a。否则,那组成的组数就小于a组,那么此时所有数都分组,就是(x+y+z)/3,此时组数小于a组,那么种类数的条件一定能满足。
同理可证,x,y,z,d,每组4个人,至少一个x和y和z,则结果也是一样,min(x,y,z,(x+y+z+d))。更多的数也是这样推。
再拓展思考一下,要是是n种数,1~n-1种数有效,每组数有n个,至少m个不同有效种类数。问最多组成多少组?就贪心的一下选数目最多的m个有效种类数就可以了。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
typedef long long ll;
int main()
{
int T;scanf("%d",&T);
while(T--)
{
ll a,b,c;scanf("%lld%lld%lld",&a,&b,&c);
ll x = min(a,b);
ll y = a + b + c - 3 * x;
if(y >= 0)
{
printf("%lld\n",x);
}
else
{
printf("%lld\n",(3 * x + y) / 3);
}
}
return 0;
}
二分:
#include <cstdio>
#include <algorithm>
#include <algorithm>
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
int main()
{
int n;scanf("%d",&n);
while(n--)
{
int a,b,c;scanf("%d%d%d",&a,&b,&c);
int r = min(a,b),l = 0;
int sum = a + b + c;
int ans = 0;
while(l < r)
{
int m = (l + r + 1) >> 1;
if(m * 3 == sum)
{
ans = m;
break;
}
else if(m * 3 > sum)
{
r = m - 1;
}
else
{
ans = m;
l = m;
}
}
printf("%d\n",ans);
}
}