Codeforces刷题记录

目录

Codeforces Round 953 (Div. 2)

Codeforces Round 955 (Div. 2)

Educational Codeforces Round 167 (Rated for Div. 2)

Codeforces Round 948 (Div. 2)

Codeforces Round 941 (Div. 2)

Codeforces Round 940 (Div. 2) and CodeCraft-23

Codeforces Round 939 (Div. 2)

Codeforces Round 945 (Div. 2)

Codeforces Round 932 (Div. 2)

Codeforces Round #956 (Div. 2) and ByteRace 2024

Codeforces Round 931 (Div. 2)

Codeforces Round 930 (Div. 2)

Codeforces Round 912 (Div. 2)

Codeforces Round 915 (Div. 2)

Codeforces Round 960 (Div. 2)

Codeforces Round 961 (Div. 2)


等八月份学完知识一定回来补题)

Codeforces Round 953 (Div. 2)

A:n本书编号为1~n,第i本有ai页,分为两堆,每堆中取编号最大的一本,求页数最多能取多少

思路:最后一本必取,找出除最后一本外的最大的页数即可

A代码

B:n个包子,可以让前k(任意)个包子的价格为b-i-1,剩下的包子价格都为a,求最多可以卖多少钱

思路:分情况:如果b比a还要小,那么全卖a就是最优解;否则就找出b-i+1和a相等的位置k,k之前用第一种方法卖,k之后用第二种

B代码

C:找出一个n的全排列P使得所有的|P1-1|+|P2-2|+|P3-3|+......+|Pn-n|等于k

思路:因为是排列,所以有一个位置a[i] != i那么就一定会有另一个位置a[j] != j

考虑初始数组为1~n

第一种情况:将两个数对换位置后可使得结果增加|i-j|*2;

另一种情况:将某个数插入到前面然后令数列整体后移,结果为|i-j| + 区间长度,仍为|i-j|*2;

可得出如果k为奇数则必定无解,剩下的就是双指针l = 1,r = n从两边开始互换答案累加,注意不要超过k,如果互换之后答案超过了k那么就取消这次互换然后让左右任意一个指针移动一步继续操作,不需要互换的地方a[i]=i

C代码

D:n个人参加选举,每人固定投票为a[i],额外有c票会投给当前人中序号最小的,票数相同时序号最小的人获胜;其中可以进行如下操作:去掉i个人,并将他们的票数视为额外票数;求每个人要想拿到冠军最少需要排除几个人

思路:

第一种情况:当前i == 1并且a[i]加上c就是最大的人 或者 当前的a[i]是最大的人并且当前的a[i]大于c+a[0] 则输出“0"(即把额外的票都给第一个人后当前的a[i]仍为全场最大或者i == 1并且a[i]为全场最大)

第二种情况:记数组中最大值为maxnum,若a[i]的值不为最大,则需要将前i-1个人都排除掉才能将额外票加到自己身上,此时若总票数大于maxnum则输出i-1(即不管maxnum的位置在前面还是后面都没有影响),否则需要把maxnum的那一个人也去除掉,输出i(即maxnum肯定在后面且比当前前缀和大)

D代码

E:给两个01序列a、b,有如下两种操作:a[i] = a[i+2] = 0则可将b[i+1]置为1;b[i] = b[i+2] = 1则可将a[i+1]置为1;给出n个询问区间求该区间中的a[i]最多有多少个1

思路:b[i]可被a[i-1]和a[i+1]影响,a[i]可被b[i-1]和b[i+1]影响,也就是a[i]最多能影响到a[i-2]和a[i+2];

即询问区间[l,r]中[l+2,r-2]的答案是和整体一样的;

可以先求出原整体序列的新序列nb[i]和na[i],然后对其求前缀和;

b[i]可以被a[i]中的0影响,而a[i]中的0不能被b[i]影响,所以先让a[i]给b[i]操作,然后b[i]再回去给a[i]操作

每次询问长度小于4直接暴力求,否则求[l+2,r-2]的前缀和然后再对剩余四个端点单独求解即可,求解过程要注意b[i]和nb[i]在什么情况下才能用(即上面所推导的i只能影响长度为2的区间),长度大于4的时候b[l+2]和b[r-2]都可以被改变,所以用nb就是最优

E代码

F:后面再补


Codeforces Round 955 (Div. 2)

A:给出两对比分x1:y1和x2:y2求前者变为后者的过程是否可以满足任意时刻x,y不等

思路:显然要使两比分不相等只能让x1,y1中的较大者先变化,然后再看较小者增加后是否又超过了较大者即可

A代码

B:给定常数x,y,有k次操作,每次可使x加一,当x能被y整除时x变为x/y,求x最终值

思路:求出y-y%x的值后用k减去这个值,同时让x加上这个值

也就是先让x满足x被y整除然后一直除下去直到x+k小于y或者k为0为止,当x为1的时候x的最终结果为1+k%(y-1),其他情况正常计算即可

B代码

C:n张牌顺序抽取,每张牌有序号ai,求有多少个不相交区间满足区间和在[l,r]之间

思路:若a+b满足,a+b+c也满足则最优解可能为a+b和c,主要在于c是否能单独满足

所以按照贪心思路进行队列前缀和操作,一旦满足条件即可记录答案+1同时前缀和清零,前缀和超出范围时就不断让队头出队依次判断是否满足即可

C代码

D:给定一个数值矩阵和01矩阵,01代表两种不同的山,数值代表山的海拔,可以操作任意次k*k的矩阵,让该子矩阵数值整体+c,求是否能满足两种山海拔之和相等

思路:根据01分为两种山求出两山全部的海拔之差NUM,然后直接枚举所有的k*k矩阵中的01数量之差,因为每次操作造成的收益都是k*k矩阵中01之差的倍数

求出x个01之差后可以列出等式:A1X1 + A2X2 + A3X3 + ...... = NUM,其中A为未知量

也就是让任意数量的任意X1~Xn之和等于NUM,即使X1~Xn的最大公约数能被NUM整除,根据裴蜀定理求解即可

D代码

E:数位dp不熟练后面补

F:给出一个n个元素的数组a,每次修改其中的一个值,求第一次操作之前和每次修改之后要想使a数组不降序排列要排序的最小子区间

思路:

根据题目描述可以把区间分为三部分:[1,L],[L,R],[R,N]

其中1~L和R~N都是数组中满足不降序的最长前后缀,L~R为存在逆序的区间

要使整个数组不降序,则要满足[L,R]中的最小值大于等于前缀中的最大值,[L,R]中的最大值小于等于后缀中的最小值

也就是找到前缀中第一个大于[L,R]中最小值的位置和后缀中第一个大于等于[L,R]最大值的位置,同时要注意后缀中元素小于前缀的可能,所以后缀要找到第一个大于等于max([L,R],a[L-1])的位置

可以用通过维护违反了单调性的位置i,最大的i和最小的i就是区间[L,R],找出该区间的最大最小值再二分即可,可以用很多方法求解,例如set(能排序的)和线段树(能求区间最值的)加二分来实现

F代码


Educational Codeforces Round 167 (Rated for Div. 2)

A:给n个硬币坐标(x,y),初始在原点(0,0)处,可以朝八个方向移动,每次移动后硬币纵坐标都会-1,问每个硬币是否有可能被拿到

思路:最坏情况每次都斜着走恰好和硬币下落相遇,其余情况为一部分斜着走剩下一部分竖着走等硬币下落或者不可能拿到,由于我们先动,也就是只需要判断每个硬币的纵坐标是否满足y+1 >= 0即可

A代码

B:给出两个字符串,求包含a为字串且包含b为子序列的字符串的最小长度

思路:a,b长度小于等于100,暴力枚举b作为a的子序列的最大字符个数即可

B代码

C:n个人,2场电影,每个人对这两场的电影为0、1或-1,现给出这n个人对这两场电影的评价,若安排一个人只看一场电影,求两场电影中评价最低的最大可能值

思路:分情况:

评价两场都为-1,则两场必定有一场评价-1;都为1,则必定有一场+1;都为0则不需要考虑;

一场评价为0,另一场评价为1则给另一场+1,若为-1则选择评价为0的那场;一场-1一场+1则必定考虑+1;

最终可以得到四个变量:ans1(第一场绝对增加的值),ans2(第二场绝对增加的值),sub(两场必定有一场-1的次数,即a[i]=b[i]=-1的情况),add(两场必有一场+1的次数,即a[i]=b[i]=1的情况)

最后分配sub和add给ans1和ans2让其尽量平衡输出较小值即可

C代码

D:有n个装备,第i个装备制造需要a[i]个相同类型金属,融化可以获得b[i]个原类型金属,每次制造和融化都能获得1经验,先给出m个不同类型的金属,数量为ci,求最大能获得的经验数

思路:乍一看像是贪心但又感觉复杂度爆炸,后来一想既然ai <= 1e6那么就dp枚举出1e6范围内的所有最优解,大于1e6的时候就用贪心直到其小于1e6即可

贪心:当一个金属ci数量满足ci >= ai的时候,一定是选择ai - bi最小的最划算

用v[i]表示金属数量为i时的最划算的一次锻造+融化所减少的金属数量;

用dp[i]表示金属数量为i时能够锻造+融化的次数

v[i[初始设为正无穷,可得出v[i] = min(v[i],v[i-1])(也就是只有前面金属数量小于最小的ai时是没有办法操作的,剩下的情况只需要找出最小的花费即可)

dp[i]初始为0,可得出dp[i] = max(dp[i],dp[i-v[i]]+1)(即有i个金属时的最优解为i减去当前最优的一次花费后的最优解次数+1,因为v[i]是当前最划算的一次最小花费数)

当ci > max(ai)时,只需要对ci进行( ci-max(ai) ) + 1次v[max(ai)]操作即可让c变为小于max(ai)的数,把前面的收益再加上dp[c]即为所求

最后答案要*2,因为上面表示的都是锻造+融化的次数

D代码

E、F:后面再补


Codeforces Round 948 (Div. 2)

A:n次操作每次在顶端放下一个正方形或者取下一个正方体,问n次操作结束后能否满足正方体堆叠高度正好为m

思路:首先只有n >= m的时候才可能有答案,然后还要保证n > m的那一部分为偶数

A代码

B:给出一个整数x,求一个长度小于等于32的数组a,要求:ai的值只能为0、1或-1;ai给数组带来的收益为ai * 2^i;不存在ai != 0且ai+1 != 0的位置。构造一个这样的数组使得数组总收益为x

思路:一个int范围内的整数肯定可以用32个以内的2的倍数来构成,所以优先考虑只加(ai = 1)的情况,构造出一个只包含1且收益为x的数

你可能感兴趣的:(算法)