奥运会正在如火如荼的进行着,金牌榜上也有许多队伍需要排名。你需要选择三个整数Pg,Ps和Pb,分别表示每获得一块金、银、铜牌所对应得分。并且满足1000>=Pg>=Ps>=Pb>=1.队伍将依据他们获得的分数进行排序(高分在前)。现在,为了使你所在的队伍排名尽可能的靠前,由你来选择Pg,Ps,Pb。
1<=n<=15
0<=G,S,B<=100000
显然暴力枚举各个分数,然后T炸天
考虑优化:
枚举Pg,
枚举Ps,
到枚举Pb时,
设第i个队伍Pg,Ps的得分是 s u m i sum_i sumi,
那么第一个队伍要赢过它,
假设Pb是num,就有:
s u m 1 + P b 1 ∗ n u m > = s u m i + P b i ∗ n u m sum_1+Pb_1*num>=sum_i+Pb_i*num sum1+Pb1∗num>=sumi+Pbi∗num
即 ( P b 1 − P b i ) ∗ n u m > = s u m i − s u m 1 (Pb_1-Pb_i)*num>=sum_i-sum_1 (Pb1−Pbi)∗num>=sumi−sum1
然后我们讨论 ( P b 1 − P b i ) (Pb_1-Pb_i) (Pb1−Pbi)
第一种:
> 0 >0 >0
那么就有 n u m > = ( s u m i − s u m 1 ) / ( P b 1 − P b i ) num>=(sum_i-sum_1)/(Pb_1-Pb_i) num>=(sumi−sum1)/(Pb1−Pbi)
这时候如果 s u m i − s u m 1 < = 0 sum_i-sum_1<=0 sumi−sum1<=0则没贡献,否则存在 n u m > 0 num>0 num>0使1胜i,将不等式计入
第二种:
< 0 <0 <0
那么就有 n u m < = ( s u m i − s u m 1 ) / ( P b 1 − P b i ) num<=(sum_i-sum_1)/(Pb_1-Pb_i) num<=(sumi−sum1)/(Pb1−Pbi)
这时候如果 s u m i − s u m 1 > = 0 sum_i-sum_1>=0 sumi−sum1>=0则没贡献,否则则存在 n u m > 0 num>0 num>0使1胜i,将不等式计入
第三种:
= 0 =0 =0,
那么这时候只需要满足 s u m 1 > = s u m i sum_1>=sum_i sum1>=sumi即可
对于所有要求 n u m < = 某 个 数 num<=某个数 num<=某个数的不等式,我们将所有的个数加起来表示为选择分数为1时最多能战胜的队伍,
然后我们将分数递增的去枚举,当越过一个>=时答案+1,越过一个<=答案-1即可
#include
#include
#include
#include
#include
#include
#define rep(i, st, ed) for (int i = st; i <= ed; i++)
#define rwp(i, ed, st) for (int i = ed; i >= st; i--)
#define mt(x) memset(x, 0, sizeof(x))
#define mp(x, y) memcpy(x, y, sizeof(y))
#define lson(x) x * 2
#define rson(x) x * 2 + 1
#define M 1000
#define N 20
using namespace std;
typedef long long ll;
struct Code {
int A, B;
Code(){};
Code(int a, int b) {
A = a, B = b;
}
}tmp[N];
struct Node {
int G, S, B;
}C[N];
int f[N][2], zyf[M+5], sum[N], n, max1, max2, max3, maxn = -1;
int read(int &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s >= '0' && s <= '9') { x = x * 10 + (s - '0'); s = getchar(); }
return x * f;
}
void write(int x) {
if (x < 0) printf("-"), x = - x;
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
bool cmp(Code a, Code b)
{
return a.A < b.A;
}
int main() {
read(n);
rep(i, 1, n) read(C[i].G), read(C[i].S), read(C[i].B);
rep(k, 1, 1000)
rep(l, 1, k) {
int num = 0, cnt = 0;
rep(i, 1, n) sum[i] = C[i].G * k + C[i].S * l;
rep(i, 2, n) {
double num1 = sum[i] - sum[1], num2 = C[1].B - C[i].B;
if (!num2) { num += (sum[1] >= sum[i]); continue; }
if (num2 < 0 && num1 >= 0) continue;
if (num2 > 0 && num1 <= 0) { num++; continue; }
if (num2 > 0) tmp[++cnt] = Code(ceil(num1 / num2), 1);
else tmp[++cnt] = Code(floor(num1 / num2), 0);
}
sort(tmp + 1, tmp + cnt + 1, cmp);
int L = 1, now = 0;
rep(i, 1, cnt) if (!tmp[i].B) num++;
while (L <= cnt) {
int i = L, willcut = 0;
if (tmp[i].B) num++; else willcut--;
while (tmp[i + 1].A == tmp[i].A && i + 1 <= cnt) {
if (tmp[i + 1].B) num++; else willcut--;
i++;
}
if (num > maxn && tmp[i].A >= 1 && tmp[i].A <= l)
maxn = num, max1 = k, max2 = l, max3 = tmp[i].A;
L = i + 1, num += willcut;
}
}
if (maxn == -1) printf("1 1 1\n"); else printf("%d %d %d\n", max1, max2, max3);
return 0;
}