Codeforces ICPC那场

在许多题目中,我原来感觉第二题应该是不难的,结果难的我都不想做了,所以发一下第二题的题解。

题目链接 : 点击这里

题目的意思便是对一个列表,任意选择范围内的索引i ,使A[i] -= 2,A[(i+1)%len(A)] += 1,我的第一想法便是用差分,使差分列表全部为零即可,但是操作就变得无规律了

为什么我会想到用差分呢,因为改变后的列表都为[n]*(len(A)),其中的n我们并不确定,可能是出现次数最多的元素,也可能是其他元素,但对于任意一个正确答案,只有其差分数组是有规律的,都为【0】乘len(A).


但最后我错了,先给大家看一下正确的代码:

    import sys
    inp = lambda: sys.stdin.readline().rstrip()
    Inp = lambda: [*map(int, sys.stdin.readline().split())]
    from bisect import bisect_left, bisect_right
    from math import gcd
    for _ in range(int(inp())):
        n, = Inp()
        A = Inp()

        C = [0]*n
        i = 1
        for _ in range(30):
            for j in range(n):
                if A[j]&i:
                    C[j] += i
                    A[j] += i
                    A[(j-1)%n] -= 2*i
            i <<= 1
    
        if -min(C) <= min(A) == max(A):
            print(sum(C)-min(C)*n)
        else:
            print(-1)、

接下来解释一下代码:我们先把列表中的每个数字看成二进制数字,我们要把每个二进制变为一样的,有个结论:在二进制数字中,每次操作都可以看成用高一位的1来换去本位的1,逆向思维,也就相当于用本位的1来换取高一位的1 ,而且大家应该发现了,对每次操作i位置上的1是,操作A[(j-1)%n]这个数字是对这个数字的i位置上的1是没有影响的,即使A[(j-1)%n]数中的i+1位置上为0,可以用更高位置上的1分解来替换的。
二进制操作数中第i位是可以进行i次操作的。
-> 为什么要取30位的二进制呢?
因为30位的二进制数字可以表示2^30−1=1073741824−1=1073741823,而数据范围是1e9,完全是可以包含所有数字的

->这道题只要最后可以把A变为全是元素0的列表,就可以把列表变为元素相同的列表,因为当元素全为k时,我们可以通过len(A)次操作变为元素全部是元素是k-1的,那么我们直接让所有元素全部通过操作可以变为全是0的的话,设答案为元素全是k的列表,通过len(A)*k此操作变为全是0的,鉴于不知道k的具体值为多少,我们只要取一个每个数变为0的可操作次数中最小值,即所有数都可以通过这个操作,那么这个值就是最后的k值**

->为什么次数大的一定会经历与次数小的一样的变化过程呢?
就比如举个例子:数字i通过5次操作变为0,数字j通过3次操作变为0,那么数字i可以通过5-3=2次操作变为j,原理就是这样的。

posted @ 2024-11-21 14:27  fafatadie  阅读(19)  评论(0编辑  收藏  举报