BestCoder Round #39

-------好久没更新博客了,发现还是需要不断总结才能进步,所以还是把最近打的一些比赛记录一下。

T1:Delete (hdu 5210)

题目大意:

给出n个数,然后要删掉k个,要求剩下的数中 不同的数个数最多。

题解:

贪心水题,尽可能先删出现次数多的。数据范围很小直接暴力就好。如果n更大的话可以用堆。


T2:Mutiple (hdu 5211)

题目大意:

给出一个长度为n(<=10000)的数列,数列中元素互不相同且都小于等于n。对于每个数Ai,求出它右边第一个满足Aj是Ai的倍数的j.

题解:

看到n的范围,我就感觉是n*sqrt(n)来做的。于是可以从右往左,用Ci表示当前满足Ak是i的倍数的最小的k.碰到一个数,求出他的所有约数,然后更新约数的C.对于Ai的答案,就是C[Ai].

看了官方题解,才发现可以nlogn来做。

从右向左查看序列
维护一个数组p[1..10000]表示该数上一次出现的位置
遇到一个数就暴力查看它的所有倍数,取最小值即可


T3:Code (hdu 5212)

题目大意:

给出一个长度为n的数列A,求sigma( gcd(A[i],A[j])*(gcd(A[i],A[j])-1) )  mod 10007.  n<=10000

题解:

这题比赛的时候没想出来,实在是太弱了..

官方题解看不懂,看了大神们的代码,和官方题解毛关系都没有。

思路是枚举gcd=x,然后看有多少对gcd=x计算总和。

f[i]表示gcd是i的倍数的有多少对,g[i]表示gcd=i的有多少对。

那么f[i]=(cnt[i]+cnt[i*2]+cnt[i*3]...)2,cnt[i]表示数列中i的个数。

g[i]=f[i]-g[i*2]-g[i*3]-g[i*4]...

求出了g[i],累加即可。


T4:Lucky (hdu 5213)

题目大意:

给出长度为n的数列A和一个数K,有m个询问,询问有多少对l1<=i<=r1,l2<=j<=r2满足Ai+Aj=K. n,m<=30000;

题解一:O(m*sqrt(n)*log(n))

主要思想是分块.f[x][y]表示i在第x个块中,1<=j<=y的答案,这个很容易预处理出来.那么可以O(1)得到i在第x个块中,

l<=j<=r的答案(f[x][r]-f[x][l-1])。

对于询问l1,r1,l2,r2. 利用f数组搞出l1,r1之间的块的答案,然后对于两端不完整的块在[l2,r2]中的线段树中暴力计算。

写个可持久化线段树就好啦。

然后我代码写的丑,被卡常数了...于是照着大神的代码打,把块的大小从sqrt(n)改成100,写个读入优化,把数组扣的小一点,就可以卡过去了。

题解二:O(m*sqrt(n))

复杂度好代码好写秒杀前面的方法.

把一个询问拆成4个询问.

Ans(l1,r1,l2,r2)=Ans(1,r1,1,r2)-Ans(1,l1-1,1,r2)-Ans(1,r1,1,l2-1)+Ans(1,l1-1,1,l2-1);

把Ans(1,L,1,R) 看成区间[L,R]的一个询问,就可以莫队了.


人太水,比赛的时候只A了前2题,Rating掉了.发现BC的题目还是挺不错的,以后会坚持做下去。

原文地址:https://www.cnblogs.com/vb4896/p/4462720.html