球队比赛平局问题

编程题1

http://www.nowcoder.com/questionTerminal/ff518f3162c849b9a84d1fab8e7179be

题解

难度:简单

知识点:数学问题

分析:

在本题中,踢赢比赛得一分,输了不等分也不见分,
那么(1)总分一定等于n;同时要想是平局n%3=0;(2)还没有踢的比赛(n-k),要能弥补(d1+d2)的分数差,即n-k≥d1+d2;(3)满足以上两点的情况时,根据差值情况,有4种情况,如下:
“1队>2队或1队<2队“ 与 “2队>3队或2队<3队”组合,假设1队的得分情况是m。
① 当1队>2队,2队>3队时,3支队伍的得分情况是:
m(max)
m-d1
m-d1-d2(min)  k=3m-2d1-d2
在该情况下,1队得分最多,3队得分最少。
要想达到平局,必须追上1队的成绩,至少还需要进行“2d1+d2”场比赛,所以剩下的场次(n-k)≤(2d1+d2),并且剩下的场次仍能被3平分才能继续保持平局。

② 当1队>2队,2队<3队时,3支队伍的得分情况是:
m
m-d1(min)
m-d1+d2  k=3m-2d1+d2
在该情况下,1队3队得分最多的要看d1d2的大小,2队得分最少。
当d1≥d2时,1队的得分最多;此时要想追上1队的成绩需要“2d1-d2”场,则(n-k)≤(2d1-d2)
否则3队得分最多, 此时要想追上3队的成绩需要“2d2-d1”场,则(n-k)≤(2d2-d1)

③ 当1队<2队,2队>3队时,3支队伍的得分情况是:
m
m+d1(max)
m+d1-d2  k=3m+2d1-d2
在该情况下,2队得分最多,1队3队得分最少要看d1d2的大小。
当d1≥d2时,1队的得分最少;否则3队得分最少。
要想达到平局,必须追上2队的成绩,至少还需要进行“d1+d2”场比赛,所以剩下的场次(n-k)≤(d1+d2)。

④ 当1队>2队,2队<3队时,3支队伍的得分情况是:
m(min)
m+d1
m+d1+d2(max)  k=3m+2d1+d2
在该情况下,1队得分最少,3队得分最多。
要想达到平局,必须追上3队的成绩,至少还需要进行“d1+2d2”场比赛,所以剩下的场次(n-k)≤(d1+2d2)。
不管在哪种情况下,要想达到平局,最后任意一个队伍的得分一定不能超过n/3。
通过上面的分析,可以有2种解题方法:利用剩余场次,以及利用最高队伍的得分情况,而这两种方法的大前提都是第一队m(基础)有解才可以。

方法1:利用最高得分列关系式

import java.util.Scanner;

public class Main{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
            int t = Integer.parseInt(sc.nextLine());

            for(int i=0;i<t;i++){
                String s = sc.nextLine();
                String[] ss = s.split(" ");
                long n = Long.parseLong(ss[0]);
                long k = Long.parseLong(ss[1]);
                long d1 = Long.parseLong(ss[2]);
                long d2 = Long.parseLong(ss[3]);

                // 利用最高分解决
                String res = solve(n,k,d1,d2);

                System.out.println(res);
            }

    }


    private static String solve(long n, long k, long d1, long d2) {

                if(n%3!=0 || n-k < d1+d2 ){
                    return "no";
                }

                // 因为是以第一队为基础,所以第一队有解是大前提。
           // 第1种情况下的1队得分最多,
           long m1 = k + 2*d1 + d2;


           // 第2种情况下的最多得分队伍
           long m2 = 0;
           if (d1>=d2){
               m2 = k+2*d1-d2; //1队大
           }else{
               m2 = k-d1+2*d2;  //3队大
           }
           long m2m = k+2*d1-d2; // 此时1队得分

           //第3种情况下,2队得分最多
           long m3 = k+d1+d2;
           long m3m = k-2*d1+d2;  // 此时1队得分

           //第4种情况下3队得分最多
           long m4 = k+d1+2*d2;
           long m4m = k-2*d1-d2;  //此时1队得分


           if((m1>=0 && m1%3==0 && m1/3<=n/3) 
                   || (m2>=0 && m2%3==0 && m2/3<=n/3 && m2m>=0 && m2m%3==0) 
                   || (m3>=0 && m3%3==0 && m3/3<=n/3 && m3m>=0 && m3m%3==0) 
                   || (m4>=0 && m4%3==0 && m4/3<=n/3 && m4m>=0 && m4m%3==0)){
               return "yes";
           }

            return "no";
    }
}

方法2:利用利用剩余场次列关系式

import java.util.Scanner;
public class Main{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
            int t = Integer.parseInt(sc.nextLine());

            for(int i=0;i<t;i++){
                String s = sc.nextLine();
                String[] ss = s.split(" ");
                long n = Long.parseLong(ss[0]);
                long k = Long.parseLong(ss[1]);
                long d1 = Long.parseLong(ss[2]);
                long d2 = Long.parseLong(ss[3]);

                // 利用剩余比赛场次解决
            String res = solve2(n,k,d1,d2);

                System.out.println(res);
            }

    }

    private static String solve2(long n, long k, long d1, long d2) {
            long m1 = k + 2*d1 + d2;  //情况1
            if(m1 >= 0 && m1 % 3 == 0){ //m有解是大前提
                long left = (n - k) - (2*d1  + d2);  //需要2d1+d2才能让两个较低的追上最高的达到平局,
                if(left >= 0 && left % 3 == 0){ //那么剩下的场次要继续能被3整除才能继续保持平局。
                    return "yes";

                }
            }

            long m2 = k + 2*d1 - d2;//情况2
            if(m2 >= 0 && m2 % 3 == 0){
            long left;
                if(d1 >= d2){
                    left = (n - k) - (2*d1 - d2);
                }else{
                    left = (n - k) - (2*d2 - d1);
                }

                if(left >= 0 && left % 3 == 0){
                    return "yes";
                }
            }

            long m3 = k - 2*d1  + d2; //情况3
            if(m3 >= 0 && m3 % 3 == 0){
                long left = (n - k) - (d1 + d2);
                if(left >= 0 && left % 3 == 0){
                    return "yes";
                }
            }

            long m4 = k - 2* d1 - d2; //情况4    
            if(m4 >= 0 && m4 % 3 == 0){ 
                long left = (n - k) - (d1 + 2*d2 );
                if(left >= 0 && left % 3 == 0){  
                    return "yes";
                }
            }

        return "no";
    }

}
全部评论
为啥测试用例d1+d2还能大于k啊?一共踢n场球,每支队伍初始分数不是应该为0么,那么踢了k场球任意一支队伍的最高得分不是应该为k么,输了又不扣分,d1+d2不是应该小于等于k么???求解答
点赞 回复 分享
发布于 2020-09-05 16:29
思路分析有点小问题,两种代码实现也都有问题(第一种无法AC,第二种虽然AC了,但是可以构造出反例,比如 6 3 0 3这个样例两种方法都输出yes,正确答案是no)。思路分析里n-k不需要大于d1+d2,应该是大于min(d1, d2),且(n-k)≤(2d1+d2)处的<=应为>=,后面同位置处的不等号都反了。第一种代码实现,只考虑最大得分和第一队得分是错的,应该是考虑最大得分和最小得分的合理性,即得分为整数且最大得分小于等于n/3,最小得分大于等于0。第二种代码实现,考虑第一队得分是错的,应该考虑最小得分,代码纠正后其实就是第一种实现的变形,核心逻辑判断完全一致。 最后,小小吐槽一下,牛客网给题目出官方题解这种行为值得点赞,但是既然要出题解拜托能不能用心一点,写的代码连自家测试用例都过不了也是醉了emmmm
点赞 回复 分享
发布于 2020-08-05 22:39

相关推荐

赛博小保安:你这简历没啥大问题的,经历技能也足够了,问题应该就是出在出身了,学院本就是这样,HR忙着跟92的勾搭呢,哪有心思看我们这些双非😿😭
点赞 评论 收藏
分享
用微笑面对困难:加急通知你不合适,也很吗有礼貌了你。
点赞 评论 收藏
分享
评论
4
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务