【math】【codeforces】451A Predict Outcome of the Game

http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=52099

有三只球队A B C,一共有n场比赛,然后现在进行了k场,不知道输赢,只知道A队伍和B队伍的胜场差是d1,B队伍和C队伍的胜场差是d2,

问这样比赛是不是可能出现平局,注意每一场比赛没有平局。

首先减枝:如果n%3 != 0,肯定不会使得三个队伍平手,输出“no”。

减枝后判断是否可能平局,需要进行两次检查:

一、第一次检查就是对于前k场比赛的结果分配是否合法。

怎样合法呢,就是最少的赢的数量是0次,因为对于每一局比赛,都会有一个赢的队伍,将这个1分配给A、B或C队,不会有0次以下的胜场数。

那么就设赢的最少的队伍数是x,其他的队伍是在这个基础上加d1、d2的组合

合法的条件就是x大于等于0,并且三个队伍赢的总和是3x+f(d1, d2),减去f(d1, d2)后是3的倍数。

d1,d2是差的绝对值,所以有四种情况:

d1>0 && d2>0 || d1>0 && d2<0 || d1<0 && d2>0 || d1<0 && d2<0

1、d1>0 && d2>0 最小的是C 设三个队胜场分别为x+d1+d2,x+d2,x

2、d1>0 && d2<0 最小的是B 设三个队胜场分别为 x+d1,x,x+d2

3、d1<0 && d2>0

这个要分析:

最大的是B无疑问,但最小的是A还是C取决于d1和d2的大小关系,

A=B-d1,C=B-d2

依然设最小的是x,B的值就是x+max(d1, d2),另外一个队的值就是x+abs(d1-d2)

之后在第二步抹平的时候也很简单:

最小的这个抹平方式就是加上他和B的差距max(d1, d2),

另一个队抹平的方式就是加上max(d1, d2)-[max(d1, d2)-min(d1, d2)] = min(d1, d2)

所以总共的抹平就是d1+d2

4、d1<0 && d2<0最小的是A 设三个队胜场分别为 x,x+d1,x+d1+d2

二、第二次检查就是将剩余的n-m场分配到胜场最少的、胜场次少的队伍上使胜场相同,之后有多余的场数就给3个队伍平均分配。

所以就是将第一步已经找出的3个队伍胜场的排列抹平,然后判断剩余的场数能否被3整除即可。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 int main(){
 5     int T;
 6     ll n,m,d1,d2;
 7     scanf("%d",&T);
 8     while (T--){
 9         scanf("%I64d%I64d%I64d%I64d",&n,&m,&d1,&d2);
10         ll s,d,s1,s2,s3,D1,D2,d3,k=n-m;
11         d=m-(d1+2*d2);
12         s=k-(2*d1+d2);
13         D1=m-(d1+d2);
14         s1=k-(max(d1,d2)+abs(d1-d2));
15         D2=m-(max(d1,d2)+abs(d1-d2));
16         s2=k-(d1+d2);
17         d3=m-(2*d1+d2);
18         s3=k-(d2*2+d1);
19         if ((s % 3==0 && s>=0) && (d>=0 && d % 3==0)) puts("yes");//d1>0 && d2>0
20         else if ((s1 % 3==0 && s1>=0) && (D1>=0 && D1 % 3==0)) puts("yes");//d1>0 && d2<0
21         else if ((s2 % 3==0 && s2>=0) && (D2>=0 && D2 % 3==0)) puts("yes");//d1<0 && d2>0
22         else if ((s3 % 3==0 && s3>=0) && (d3>=0 && d3 % 3==0)) puts("yes");//d1<0 && d2<0
23         else puts("no");
24     }
25     return 0;
26 }
原文地址:https://www.cnblogs.com/miaowTracy/p/5385211.html