santisify Site

Back

Codeforces Round 912 Div2Blur image

A Halloumi Boxes#

题目大意#

给定一个数组A,我们可以对数组惊醒多次操作,操作如下: 我们可以将数组中的某一段倒置,但是长度不能超过K,例如:反转子数组意味着选择两个索引i和j(其中 1 <= i <= j <= n ) 并将数组 a1,a2,,ana_1,a_2,\cdots,a_n 改为 a1,a2,,ai1,aj,aj1,,ai,aj+1,,an1,an(ji+1k)a_1,a_2,\cdots,a_{i−1},a_{j},a_{j−1},\cdots,a_{i},a_{j+1},…,a_{n-1},a_n \quad (j − i + 1 \le k )

分析#

由于可以操作多次,那么我们可以判断下k是否为1:

  1. 若k = 1时, 我们只能反转一个元素,显然是无效的, 我们就只需要判断数组是否为有序
  2. 若k > 1时,显然是可行的

代码#

B StORage room#

题目大意#

给定一个数n,和一个n*n的数组M,数组Mi,jM_{i,j} 表示为:Mi,j={aiaj,(ij)0,(i==j)(Mi,j<230)M_{i,j} = \begin{cases} a_i|a_j,(i \not= j)\\\\ 0, (i == j)\end{cases}(M_{i,j} < 2 ^{30})

让我们判断是否存在这样的一个数组a满足上式,若存在输出YES和数组a 否则输出NO

分析#

现在我有两个数x, y,如果我将这两个数进行或运算后(w = x | y), 在二进制状态下xy在某一位上有一个为1,则该位为1通过这个我们可以发现在MiM_i 中,Mi,0=aia0,Mi,1=aia1,........,Mi,n1=aian1M_{i,0} = a_i | a_0, M_{i,1} = a_i | a_1, ........, M_{i,n - 1} = a_i | a_{n - 1} , 我们可以通过与运算将aia_i 计算出来, 但是在运算时我们需要排除Mi,j(i==j)M_{i,j}(i==j); 在计算完后我们可以遍历一次M数组,判断Mi,j=aiaj(ij)M_{i,j}=a_i|a_j(i \not= j)

参考代码#

C Theofanis’ Nightmare(贪心)#

题目大意#

给定一个数组a,大小为n,现在将数组a分割成几个非空子数组,并且保证每个元素只在一个一个子数组中,例如,数组 [1,−3,7,−6,2,5]可以划分为 [1][−3,7][−6,2][5]。 这种分割的值等于i=1kisumi\sum_{i=1}^k i*sum_i ,其中k是我们将数组分割成的子数组的个数,sumisum_i 是第i个子数组的和。 这个数组的值为[1][3,7][6,2][5]=1×1+2×(3+7)+3×(6+2)+4×5=17[1][−3,7][−6,2][5]=1\times 1+2\times (−3+7)+3\times (−6+2)+4\times5=17 现在让我们求分割的最大值为多少?

分析#

先考虑每个子段的数字贡献,i* sum_i也可以转化为该子段中每个数字被加上了i次。那么就可以把乘法转化为加法。

然后考虑怎么划分子段最优,如果从前往后考虑,很难判断是否该将当前数字划分为一个新子段的起点。 因此,需要从后往前遍历,统计i∼n之间的数字总和,为了使答案尽可能大,那么只要当前数字总和大于等于0,就可以将当前位置划分给一个新的子段起点。

此时,划分出一个新的起点后,那么后面所有的数字均需要再被加上一次,不难发现,此时要加上的就是维护的数字总和。

由于第一个元素也可能被划分到一个新的子段中,为了避免重复计算,当遍历到第一个元素时,必须将当前元素视为子段起点,加上维护的数字总和。

代码#

D1 Maximum And Queries (easy version)#

题目大意#

给出一个长度为n的数组a,并进行q次询问,每次询问为: 你可以进行k次操作,每次从数组a中选择一个元素,让这个元素 + 1。 问:经过q次操作后,a1,a2,.....,ana_1,a_2,.....,a_n的与的最大值是多少 注:每次询问都是独立的,不会保留前面询问的操作结果。

分析#

由于每次询问都是独立的,那么修改不能在原数组上进行,需要将原数组元素复制到其他数组中再进行操作。 题目数据规定了n×q105n\times q≤10^5,那么可以认为最大的数据就是对长度为10510^5的数组进行一次询问。由于给出的k1018k≤10^{18} ,那么当数组中只有一个元素时,最大可能的结果为1018+10626010^{18}+10^6≈2^{60} ,因此需要一个大于60的数组记录与运算后的结果每位二进制数是多少。 对于每次询问,从二进制高位开始往低位进行遍历,每次检查当前剩余的k是否还能将数组中所有数的当前二进制位修改为1 如果可以,进行修改,并记录在答案数组中,如果不行,继续遍历更低的二进制位。 结束修改后,将数组中记录的信息转化为十进制数即可。

本题数据较大,需要注意使用左移运算需要使用1ll将1转化为long long类型再进行运算,计算花费时也要考虑如果超过操作次数就该退出检查,避免数据溢出。

代码#

Codeforces Round 912 Div2
https://santisify.top/blog/old/cf1903
Author santisify
Published at August 7, 2024
Comment seems to stuck. Try to refresh?✨