CF practice #2 solution

来源:互联网 发布:美版mac如何新建文件夹 编辑:程序博客网 时间:2024/05/18 23:13

CF practice #2 solution


题目链接

A:cf 152 div2 C

题意:有一个球,一个球门和一面墙,要把球射到墙上然后反弹到球门中,问是否可行,如果可行输出任意一个合法的与墙面接触的x坐标。球的位置和半径已知,球门横坐标为0,墙水平于x轴。

数据范围:所有坐标和数据的大小小于106

 

Solution:易知球射到墙上的横坐标越大那么反弹到下面的纵坐标也就越小。根据给的数据可以计算出当球射入球门顶部和球射入球门底部的x坐标范围,那么如果这个区间合法,其中的任意一个值均可作为答案,否则就无解,输出-1。复杂度O(1)。

B:cf 152 div2 D

题意:一个长为n的街道,分成n个格子,每个格子为商店或者房子或者什么都没有,每个商店可以买最多一个糖果,从一个格子到相邻格子的代价为1,问最少需要带多少个糖果,才能在走路的代价不超过K的情况下让每个房子都有一个糖果。

数据范围:1<=n<=5*105,0<=k<=109

 

Solution: 显然第一步是二分带的糖果的数量,然后问题转为判定性问题:带了x个糖果能否在k步内满足题意。

设第0个数为x,记第i个数为1如果这里是商店,-1如果是房子,否则为0。记p[i]为前i个数的和,那么我们最多只需要走到最后一个p[i]大于等于0的地方,如果最后一个格子p[i]都不大于等于0,那么显然无解,之后则判断最少步数是否会大于k了。

之后来考虑最优的走法,现在在第i个格子,前面的最小代价为d。

1.             如果当前的是房子且之前的总数正好为0的话,那么这时的最优则为从当前到末尾然后从末尾再走回来,即ans=min(ans,d+(n-i)*2),并用last记录这个点。

2.             如果当前是商店且到这里糖果总量刚好为0,那么如果当前是末尾的话,则需要从这里再返回到前面最近的一个last点,即ans=min(ans,d+n-last),并且走到当前位置不用再往回走的代价更新为d=d+(i-last)*2。

3.             对于每一步,d=d+1。

之后只用判断ans是否比k大就可以了。判断的复杂度为O(n)。

综上,总的复杂度为O(nlogn)。

C:cf 152 div2 E(by Eyelids)

题意:共有n个架子,每个架子上有a[i]个蜂蜜罐头。进行q次操作,每次操作从标号为u的架子随机拿下k[i]个罐头,尝一下放到架子v上。询问架子上的所有罐头已经被尝过的架子数的期望值是多少?

数据范围:1 <= n,q <= 100000, 1 <= k[i] <= 5, 1 <= a[i] <=100。

Solution:很明显是一道概率dp题,但是似乎不太容易写出方程。但经过观察可以发现,这里的k[i]和a[i]都很小,(k[i] <= 5,a[i] <= 100)可以考虑用二维状态f[i][j]表示第i个架子上有j个罐头还未被污染的概率。

直接计算拿下k[i]个状态似乎不方便转移。于是每次状态转移只考虑从u上取下一个罐头,放到架子v上,进行k[i]次转移。sigma(f[i][0])就是所要求的结果。

D:cf 151 div2 E

题意:一棵树,n个点,每个节点是个字符串,m个询问,每个询问给一个v,一个k,问v的k儿子有多少个。

数据范围:n<=105,m<=105,k<=n。

 

Solution:在求最近公共祖先的时候有一种把树对应成rmq数组的方法,使用那种方法,对于每一层建一个vector,存储该层所有节点进入数组时的的位置和出去数组时的位置,并且对于每个节点,也记录下这两个位置。该步复杂度为O(n)。

         接着对于每个询问,首先找到v的k儿子对应的层数,即depth[v]+k,然后用v的左右位置在该层中二分查找,得到一个区间,这个区间中所有的节点即为v的k儿子,然后用一个set把这些节点的字符串插入去重,最后set的size就是结果。对于每一个v,k需要记忆化,不然会Tle。

         关于复杂度的疑问:在求一段区间内有多少个相同的数的时候,有一种离线的线段树的做法,不过这样的话编程复杂度就会很大,写起来很麻烦,但是上述做法中在这里使用的是直接暴力区间的方法,理论上复杂度应该为O(m*n*log(n)),不过因为记忆化了,导致大的操作最多只会执行一次,到了最后全部都是复杂度很低的操作,导致想不出什么方法去构造出能够卡掉的数据,加上实际上程序跑的速度很快(200ms)。所以怀疑均摊的复杂度会不会是O(m*log(n)*log(n))。如果有人知道怎么算请不吝赐教。

 

E:cf 150 div1 B

题意:一个n个点,m条边的图,问是否存在九头蛇,所谓九头蛇是指两个节点u和v,并且u上连接另外s个点,v上连接另外t个点,且u连接的这s个点与连接v的t个点没有公共点。

数据范围:n<=105,m<=105。1<=s,t<=100。

 

Solution: 因为不知道公共点有多少,所以直接判v和u的size显然是不行的。

         对于每个点,用map保存这个点和哪些点有相连。枚举每一对相邻的点,判断这两个点是否有九头蛇。

1.      size(v)>=200且size(u)>=200,那么显然是存在的,因为就算这些点全是公共点也可以各分100个给u和v。

2.      其他情况,必然有一个点的节点数量少于200,枚举这些点,判断另外一个点是否与这些点有相连,然后得到公共点的数量,这里的复杂度为O(100*log(n))。用s和t减去u,v的独立点的数量,不够就用公共点去补,如果能构造成功则有解,否则无解。

无解的情况输出-1,对于有解的情况,按照上述方法构造出一组合法的解输出即可。

         复杂度为O(m*(s+t)*log(n))。

F:cf 150 div1 C

题意:一个地图,大小为(1010 + 1) × (1010+ 1) ,一个农夫站在中间,有n条指令。每次按照某条指令走,指令为r,l,u,d四种方向,然后x为走的步数,然后病毒从地图边缘入侵,感染周围四个点,但是农夫走过的点是不会被感染的,也不会去感染其他点。最后询问有多少点不会被感染。

数据范围:n<=1000。 

 

Solution:这道题可以认为是12年金华C的简化,我们关心的点就是每次走到的点的坐标,那么就是x,x+1,y,y+1,利用这些坐标,将原图离散成一个小图,每一个点(x,y)的值代表x~x+1,y~y+1矩形的面积,然后按照指令走一次,暴力染色计算面积就可以了。因为最多坐标不超过2n个,所以暴力的复杂度为O(n2)。

G:cf 141 div2 C

题意:一个2*2的正方形,每个格子为黑色或者白色,这样的正方形有16个,然后将每个正方形做如下变换,得到的仍然是合法的正方形。

1.      白色的格子:用2*2的原小正方形替换。

2.      黑色的格子:用2*2的黑色正方形替换。

给出一个n*m的图,问其中合法的正方形有多少个。

数据范围:n,m<=500。

 

Solution:设状态s(0<=s<16),s的第i位为0表示第i个格子是白色,否则黑色。首先预处理出i,j开始的2t *2t是否全为黑色,存在b中,然后用状态f[t][i][j][k]表示i,j开始的2t*2t

是否是合法的原状态为k的正方形。转移就是枚举k的每一位,根据该位是否为0看2t-1 *2t-1是否为全黑或者合法,每遇到一个合法的正方形ans++最后输出即可。复杂度O(n*m*log(max(n,m)))。

H:cf 141 div2 E

题意:n个点,m条边的图,每个点为黑色或白色。每次操作可以选择一个点,该点及其周围点颜色取反,问是否可以在k步内让所有点都为黑色,并输出方案。

数据范围:n<=100。

 

Solution:一个裸的2-sat,对于一条边a,b,颜色为c:

1.      C为白色a->b’

a’->b

b’->a

b->a’

2.      C为黑色a’->b’

a->b

b’->a’

b->a

如果2-sat得到的结果是有解的话,就在每两个对称的解集中取任一个作为解法就行。否则输出Impossible。

I:cf 135 div2 E

题意:一个长为n的停车场,车子进来总是找离现有已停车最远的可用的停车位,就是说如果有两辆车在一头一尾,这辆车一定会停在他们中间,如果有多个这样的停车位,选序号最小的。然后有m个操作,每个操作为进来一辆车或者某辆车出去,对于进来的车,输出其停靠的车位。

数据范围:1<=m,n<=2*105

 

Solution: 总结题意,就是说我们需要一个数据结构,实现3种操作:1.删除一个数。2.在某个特定位置插入一个数。3.找到一个位置,这个位置离现有的已占用的位置最远。

         首先来考虑特殊的情况:对于没有车停靠的,那么当前可用位置为1,如果有一辆车,那么当前可用位置为左端点和右端点取最优。对于删除操作,直接删除即可。

         再来考虑一般情况,对于一个可用的座位,我们有2个参数,一个是他离所有占用点最近距离是多少,另外一个是他的坐标,我们用一个集合来存储所有的可用的座位,但显然不是所有的座位都有意义,有的座位一定会等其他座位被用了以后才会开始使用,比如12345,1和5被占了,那么在3被占了之前2和4是不会被占的,那么我们集合里只存这样的空位置。一个是两个占有座位中间的位置,一个是头和末的位置,然后每一次我们从集合中选出最小的一个数占掉,接着因为这个座位被占了,可能会加入新的0~2个可用座位到集合中(因为边界),这样插入的复杂度为O(log(n))。

         同理,对于一个已占有的座位,有3个参数,左边的已占用的位置,右边的已占用的位置,坐标,删掉这个数的时候,首先把这个数产生的2个可用座位从集合中删去,然后左右的座位取中值成为新的可用座位,把这个座位插入集合,这样删除的复杂度也为O(log(N))。

         对于插入删除最左边或者最右边的情况的处理比较麻烦,需要分类讨论。

         复杂度为O(m*log(n))。

J:cf 132 div2 C

题意:一个十字用6个参数定义,a,b,c,d,x,y。满足

  • |x0 - x| ≤ a 且 |y0 - y| ≤ b 或
  • |x0 - x| ≤ c 且 |y0 - y| ≤ d

给一个n*m的图,问面积为s的不同的十字图案有多少个。

数据范围:1<=n,m<=500。

 

Solution: 枚举十字的横长度和竖长度,然后枚举一边的宽度,因为面积是已知的所以另外一边的宽度可以计算出来,然后判断是否合法累加到答案里去即可。复杂度O(n3)。

 

K:cf 132 div2 D

题意:有n个地区,m个小孩,要从1依次到n,每个地区的温度为ti,最大能忍受的温度为Ti,车里每多一个孩子就会多一度,如果车内温度超过Ti,那么每个孩子要求补偿ci块钱,一辆车经过该地区的费用为costi,问从1到n的最小花费是多少。

数据范围:n<=105

 

Solution: 显然每个地区之间的花费可以单独考虑,对于每个地区,我们要在使用多辆车减少赔偿和使用少量车减少雇佣费用来权衡。首先,如果有车过热的话,因为过热多少都不影响赔偿价格,所以一定是雇佣尽可能多的车,使其他车刚好温度到Ti,然后把剩下的孩子全部放到过热车上;如果没有车过热的话,每辆车尽可能装满;如果雇车的费用远大于赔偿费用,那么所有孩子全部都放在一辆车上,不雇佣多的车。所以对于每个地区,我们只需要在这三种方法之间取一个最小的就可以了,最后把答案累加起来输出。复杂度O(n)。

 

L:cf 132 div2 E

题意:问l到r之间的循环数有多少个。所谓循环数是指将其翻译成2进制以后,01序列有周期性,如101010。

数据范围:l,r<=1018

 

Solution:问题可以转化为求0-x之间的循环数有多少个,设x有k位,那么所有k位以下的循环数是合法的,至于k位的循环数的总数很容易求得,假设f[k]表示k位的循环数的个数,那么f[k] = 2k- sum(f[i]) ( k % i = 0 ) 。

         至于如何求长度恰好为k的循环数的数量,我们枚举k的约数q,即循环节的长度,把前 q位的数拿出来,那么比这个数小的循环节肯定是合法的,再单独判断一下和q相等的循环节生成的数是否大于x,这样g[q]表示的循环节长度为q的合法数数量就有了,按照上面的方法,再枚举q的约数d,用g[q]减去g[d],就减去了重复的循环节,这样,长度为k的循环数的数量我们也能得到了。

         两者相加即是答案,复杂度O(log(r)*log(r))。

M:cf 131 div1 A

题意:有n个任务,3台电脑,每个任务都得在特定电脑上完成,有的任务要等某些任务完成才能开始,完成一个任务要1小时,电脑切换时间如下表,问最少需要多少时间完成所有任务。

1->2 1H 1->3 2H

2->1 2H 2->3 1H

3->1 1H 3->2 2H

数据范围:n<=200。

 

Solution:仔细观察表中数据,就会发现题目其实很唬人,从1->2->3其实和从1->3是一样的代价,其余路线也是一样,就是说从1要到3还不如从1到2再到3,这样看来的话,我们机器的切换一定是1->2->3->1->2->3…,那么只需要枚举最开始是哪台机器,然后每到一个状态,完成该状态的所有工作,更新其他状态,然后进入下一个状态,直到所有任务全部完成。  

N:cf 131 div1 B

题意:0~9,每个数有a[i]个,用这些数组成一个不超过n位的数,没有前导零,问有多少种方法。

数据范围:1<=n<=100,a[i]<=100。

 

Solution:用f[i][j]表示从9~i组成j位数的方法数,则f[i][j]= f[i][j] + f[i+1][k] * c[j][j - k],因为没有前导0,所以0的时候要特殊处理,稍微修改下方程就行了。复杂度O(10*n2)。

 

O:cf 131 div1 C

题意:参见NOIP2008 传纸条

数据范围:略

 

Solution: 参见NOIP2008传纸条

Q:cf 130 div2 C

题意:n个点,m条边的无向图,建一个警察局,和警察局相连的路认为是安全的,问警察局建在哪里,使得从1到n的所有最短路中,安全路段的期望比例最大。

数据范围:2<=n<=100

 

Solution:做一遍floyd,算出两点最短路的同时算出两点最短路的数量,然后枚举每条边u,v,如果这条边在最短路上,那么num[1][u]*num[v][n]增加进i和j的安全路段数量里去,最后n个点中取安全路段数量最大的点,就是我们要的结果。复杂度O(n3)。

 

R:cf 130 div2 E

题意:大体同codeforces #151 div2 的E,询问从k儿子变成了k兄弟。

数据范围:略

 

Solution:大体做法见D题,稍改动函数即可,因为这里问的是数量,所以没有复杂度的问题。

 

S:cf 129 div1 A

题意:一个数是lucky number如果它的第一个数字和最后一个数字相同,问l到r中间有多少lucky number。

数据范围:l,r<=1018

 

Solution:问题同样可以转化为问从0到x有多少luckynumber,首先考虑位数比x少的,这个数量很容易用组合数学计算出来,主要来考虑位数和x一样的。

         枚举数的最高位,如果最高位小于x的最高位,那么中间的答案就是10q,q为中间的位数,如果最高位等于x的最高位,那么最后一位如果大于x的最高位,那么答案就是中间的数,否则答案是中间的数+1。最后把所有答案累加起来就是结果。

 

T:cf 129 div1 B

题意:有n张卡片,每张卡片正反面都有数字,每次操作可以把某张卡片翻面,问最少多少操作,让朝上的卡片数字中有数字数量超过卡片一半。

数据范围:n<=105

 

Solution: 首先找是否存在这样的数字,每个数字用map记录,遇到了就加一,如果发现多个数字数量超过一半了,取正面朝上最多的那个数字,复杂度O(nlogn)。

 

U:cf 129 div1 C(by Eyelids)

题意:给出两个由26个小写字母组成的字符串,从两个字符串中分别随机取出长度相等的子串。对两个子串对应位置上的字符进行比较,统计对应位置上相等的字母的总数,询问每次取出比较后,对饮位相同的个数的数学期望是多少?

数据范围:串长n<=2*105

 

Solution:从两个字符串中随机取出长度相等的两个子串,很明显总情况数为sigma(i * i) (1 <= i <= n),即为分母。

考虑分子,其总数即为两个子串对位置上相同的字母个数,这里可以转化为任意两个相同的字母在多少个可能的子串组合中出现过。如下图所示:

x[1], x[2] …… x[i] ……x[n]

y[1], y[2] …… y[j] ……y[n]

如果这里存在x[i] = y[j],那么可能出现的子串的组合情况为min(i, j) * min(n - i + 1,n - j + 1)

从1到n开始枚举i,同时用sum[0][], sum[1][]分别记录两个字符串(x和y)到第i位之前,包含某个字母的子串的个数。

对于当前的x[i],因为字符串y之前出现的与x[i]相同的字母的左边显然比x[i]左边的长度短,右边显然比x[i]右边的长度长,所以这里只要把(n - i + 1) * sum[1][(int)x[i] - 'a']加到总的结果里。这样就满足了x[i] =y[j](i <= j)的情况的统计

反之再计算x[i] = y[j](i > j)的情况。与上面的计算方法类似。

V:cf 128 div2 C

题意:有n张照片,dM的内存,小内存要占aM,大内存要占bM,每张照片需要xM小内存和yM大内存,问最多能存几张照片。

数据范围:1<=n<=105,d<=109

 

Solution: 直接算出每张照片需要的内存数量,排序,每次取最小的内存。复杂度O(nlog(n))。

 

W:cf 128 div2 D

题意:一个长为a,宽为b,宽为m的箱子,一个小球从 进入,速度为vx,vy,vz,小球碰撞时入射角等于反射角,问当纵坐标第一次为0的时候,x坐标和z坐标为多少。

 

solution: 对于3个方向的坐标分别计算,首先只考虑y速度计算出纵坐标为0的时间t,然后对x和z坐标分别计算出t时间之后的坐标,输出即可。

 

X:cf 128 div2 E

题意:从厂房到家里的距离为d,有n个机器人,每个机器人输入ui的汽油就能动,最多可以走di米,这个机器人可以携带ci个其他机器人。被携带的机器人也可以携带其他机器人,现在有s升油,问最多可以带多少机器人回去,以及带这么多机器人回去最少需要多少油。

数据范围:n<=105,其余<=109

 

Solution: 我们把机器人分为4类:

1.能自己走回去的,能携带机器人的

2.能自己走回去的,不能携带机器人的

3.不能自己走回去的,能携带机器人的

4.不能自己走回去的,不能携带机器人的

       先来研究第一类,这一类机器人的特点是只要付了一个人的费用,其余的均能被带回去,同理,第三类中只要有1个被带了,第三类全部都能够被带回去。对于第4类,我们可以认为其费用为无限大,并将其归到第二类去。

         所以我们有两种策略:

1.      付一个1类机器人的钱,这样1,3类都能带回去了,然后再按2的油量消耗,带尽可能多的回去。

2.      不付1类机器人的钱(可能付不起),只带2类机器人回去。

第二种情况非常好算,下面主要考虑第一种情况。

1,3类带完后,我们能够得到还能再带多少机器人回去,把2从大到小用这部分免费名额带走,然后从前到后选最小的耗油带走,直到油量不够带走任何一个机器人。

不过这样有一个问题,假设当前2中耗油最小的为5,现在手上的油量为4,那么就真不能多带走一个机器人了么?答案显然不是,如果1中有一个耗油量为3的,显然可以把本来带那个耗油为3的机器人改成带这个耗油5的,然后用油去驱动那个耗油3的。

所以2中的点还得再变化,为1类中除开最小耗油的所有机器人,2类的所有机器人,4类的所有机器人,然后我们就按照上述方法贪心选尽可能多的机器人带走就可以了,当然,这部分用油消耗带走的机器人的总数量不能超过原本的2类和4类的数量总和。

复杂度O(n*log(n))。

 代码链接