题目描述:
/**
有三只球队,每只球队编号分别为球队1,球队2,球队3,这三只球队一共需要进行 n 场比赛。
现在已经踢完了k场比赛,每场比赛不能打平,踢赢一场比赛得一分,输了不得分不减分。
已知球队1和球队2的比分相差d1分,
球队2和球队3的比分相差d2分,
每场比赛可以任意选择两只队伍进行。
求如果打完最后的 (n-k) 场比赛,有没有可能三只球队的分数打平。
输入描述:
第一行包含一个数字 t (1 <= t <= 10)
接下来的t行每行包括四个数字 n, k, d1, d2(1 <= n <= 10^12; 0 <= k <= n, 0 <= d1, d2 <= k)
输出描述:
每行的比分数据,最终三只球队若能够打平,则输出“yes”,否则输出“no”
输入例子1:
2
3 3 0 0
3 3 3 3
输出例子1:
yes
no
例子说明1:
case1: 球队1和球队2 差0分,球队2 和球队3也差0分,所以可能的赛得分是三只球队各得1分
case2: 球队1和球队2差3分,球队2和球队3差3分,所以可能的得分是 球队1得0分,球队2得3分, 球队3 得0分,比赛已经全部结束因此最终不能打平。
*/
思路如下:
暴力穷举4中可能情况 设第一队为x; 第二队为 x-d1 或 x+d1; 第三队类似推导 解出 (score1, score2, score3)的合法元组
然后看剩余的n-k能否让 (score1, score2, score3)->(n/3, n/3, n/3)
代码如下:
#include<stdio.h>
#include<iostream>
using namespace std;
typedef long long LL;
void GetABC(int i, LL a, LL *pb, LL *pc, LL d1, LL d2)
{
switch (i)
{
case 0:
*pb = a + d1;
*pc = *pb + d2;
break;
case 1:
*pb = a + d1;
*pc = *pb - d2;
break;
case 2:
*pb = a - d1;
*pc = *pb + d2;
break;
case 3:
*pb = a - d1;
*pc = *pb - d2;
break;
}
}
int main()
{
int T;
for (cin >> T; T--; )
{
LL n, k, d1, d2;
scanf("%lld%lld%lld%lld", &n, &k, &d1, &d2);
//x的四种可能解的3倍,就是第一场可能出现的解
//第一场的分数的3倍
LL x[] = {k - 2 * d1 - d2,k - 2 * d1 + d2,k + 2 * d1 - d2,k + 2 * d1 + d2};
bool flag = false;
for (int i = 0; i < 4; i++)
{
int sum = 0;
//判断第一场的分数是否为3的倍数
for (LL t = x[i]; t; sum += t % 10, t /= 10) {}
//第一场分数要合法才美剧判断
if (sum % 3 == 0 && 0 <= x[i] / 3 && x[i] / 3 <= k)
{
LL a = x[i] / 3, b, c;
//计算根据第一场x的不同情况,计算4中情况对应的第一场第二场的分数
GetABC(i, a, &b, &c, d1, d2);
if (0 <= b && b <= k && 0 <= c && c <= k)
{
LL maxNum = max(a, max(b, c));
LL diff = 3 * maxNum - a - b - c;
//剩下的场次,若先让最小的两个都抹平达到最大的一个分数,剩下的分数要是能平分给3队即可
if (n - k - diff >= 0 && (n - k - diff) % 3 == 0)
{
flag = true;
break;
}
}
}
}
if(flag)
printf("yes\n");
else
printf("no\n");
}
return 0;
}