首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >原创 | codefroces中的病毒,这题有很深的trick,你能解开吗?

原创 | codefroces中的病毒,这题有很深的trick,你能解开吗?

作者头像
TechFlow-承志
发布2020-10-09 11:52:13
5800
发布2020-10-09 11:52:13
举报
文章被收录于专栏:TechFlowTechFlowTechFlow

大家好,欢迎阅读周末codeforces专题。

我们今天选择的问题是contest 1419的C题,目前有接近8000的人通过了本题。今天这题的难度不大,但是真的很考验思维,一不小心就会踩中陷阱,我个人觉得非常有意思,适合周末动动脑。

题目链接:https://codeforces.com/contest/1419/problem/C

题意

有一个叫做Killjoy的特工发明了一种新型的冠状病毒叫做Convid-2069,专门在codeforces平台上传播。这种病毒通过rating传播,只要两个人的rating一样并且其中一个感染了病毒,那么另外一个也会被感染

这个病毒一开始的时候只有Killjoy自己感染了,他一共和n个人有联系。由于codeforces会定期举办比赛,参加比赛会改变一个人的rating,由于codeforces的规则,导致所有参赛的人的rating变动的总量为0,也就是说有人升了一定会有人降,大家的总和保持不变。已知Killjoy自己不会参赛,请问最少需要多少次比赛可以将所有人都感染。

对于每一次比赛,可以不必所有人都参与,传染的发生不需要时间,瞬间就可以传染。很容易证明,我们一定可以在有限次比赛当中将所有人都感染。

样例

首先输入一个t表示测试数据的组数(

1 \le t \le 100

),对于每一组数据第一行输入两个数,分别是n和x。n表示和Killjoy有接触的人的数量,x表示Killjoy自己的rating,(

2 \le n \le 10^3, -4000 \le x \le 4000

)。

第二行输入n个整数,表示这n个人的rating。要求输出一个整数,表示最少需要的比赛数量(

-4000 \le a_i \le 4000

)。

题解

这道题的思路非常直接,没什么弯弯绕,我们只需要观察一下样例就可以了。样例当中有三组数据刚好对应了三种情况。

我们先来看第一种情况:这n个人的rating都和x相等,那么意味着我们不需要比赛,就可以把所有人都感染了。结果当然是0,这一种非常简单,大家应该都可以想明白。

第二种情况也不难,第二种情况就是虽然大家的rating不全等于x,但是大家的总和等于x * n。也就是说rating大于x的减小到x,小于x的增加到x,刚好可以通过一次比赛让大家全部被感染,那么最终的答案就是1。这对应样例当中的68, 70的情况,x=69,很明显68的增加1,70的减去1,就可以都变成69。

前面两种理清楚了,再来看第三种情况,第三种情况也就是前面两种都不符合的情况。也就是我们通过一次比赛没办法让大家都等于x,不过这并没有什么关系,因为题目当中并没有限制rating的范围。我们完全可以让其中n-1个人全部变成x,由于要保证大家的rating变动之和等于0,所以让最后一个人来完成平衡的角色。

也就是说通过一次比赛,我们可以让n-1个人全部被感染,最后留下一个人。那么不难想出,我们只需要再多用一个回合就可以了。再多一个回合,我们可以让第n个人变成x,让一个已经感染的人来完成平衡。那么,我们用了两个回合就完成了所有人的感染。

整理一下思路,其实这题分为三种情况,第一种情况是大家全部都等于x,答案是0。第二种情况是大家可以只需要一个回合就变成x,如果上面两种情况都不满足的话,就额外再消耗一个回合即可。

这个思路也太简单了,很快我就写好了代码:

import math
 
t = int(input())
 
for _ in range(t):
    n, x = list(map(int, input().split(' ')))
    arr = list(map(int, input().split(' ')))
 
    diff = 0
    sdiff = 0
    for i in range(n):
        diff += abs(arr[i] - x)
        sdiff += arr[i] - x
 
 # 如果所有人都等于x,那么会在一开始就被感染完
    if diff == 0:
        print(0)
    # 如果可以通过一个回合让所有人的rating调整到x,那么只需要一个回合
    elif sdiff == 0:
        print(1)
    else:
        print(2)

但是很遗憾,当我提交了之后,并没有AC,而是错在了第二组数据。我想了很久,才终于想到了其中的trick。我先不说,大家先思考一下,看看能不能想到。

准备好了吗?

我们刚才列举的三种情况是没有问题的,但是我们遗漏了一种。就是这一开始的n个人当中,可能有人的rating就等于x,所以他会在第一次比赛之前就感染。我们再想想最后一种情况,我们先把n-1个人的rating调整到x,再把调整当中付出的代价交给其中一个人来承担。这也是我们需要第二个回合的原因,如果这n个人当中存在有人在开始之前就感染了,那么我们完全可以让这个已经感染的人来承担代价,这样我们就可以减少一个回合。

体现在代码当中,就是我们需要额外增加一个判断条件,判断一下这n个人当中是否存在有人的rating等于x,会在一开始的时候就被感染。如果有的话,答案就是1。

附上代码:

import math

t = int(input())

for _ in range(t):
    n, x = list(map(int, input().split(' ')))
    arr = list(map(int, input().split(' ')))

    diff = 0
    sdiff = 0
    flag = False
    for i in range(n):
        if arr[i] == x:
            flag = True
        diff += abs(arr[i] - x)
        sdiff += arr[i] - x

    if diff == 0:
        print(0)
    # 如果存在人感染,也只需要一个回合就可以完成感染
    elif sdiff == 0 or flag:
        print(1)
    else:
        print(2)

这道题其实并不难,但是很容易漏掉这种情况,这也是codeforces当中题目的魅力所在,考验我们思维的缜密与细致程度。我个人觉得还是非常有趣的,值得一做。

- END -

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-09-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Coder梁 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 题意
    • 样例
    • 题解
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档