codeforces round 160(完全)

来源:互联网 发布:淘宝卖家怎么品牌授权 编辑:程序博客网 时间:2024/06/06 09:45

又跪了。。。继续做吧,坚持!!

codeforces 261B   

先用背包处理出一个dp数组,然后枚举每一个分隔数(即前面的数再加上这个数就超过p了) 统计出所有的数量,然后直接算,,

http://www.codeforces.com/contest/261/submission/2921844


codeforces 261C

首先可以计算出m+1行有几个1 (画一画就能得出规律):即给定一个m,第m+1行的1的个数为2^(bit_count(m+1) - 1 ) 个 ,所以t肯定是2的指数次幂,否则答案为0

现在问题转换成求2到n+1中有几个数的二进制表示中有P+1个1,(2^P = t),典型的数位DP搞一下把。

dp[i][j]表示长度为i有j个1的二进制数的个数,预处理好之后直接统计即可

http://www.codeforces.com/contest/261/submission/2922990


codeforces 261D

我感觉题意好难懂啊。。。。

给你k行数,每行有n个数,然后将这n个数重写t遍相连,问你新组成的序列(总共有n*t个数)的最长递增子序列的长度为多少。

有几个要注意的地方  题目保证所有数都不超过maxb , maxb*n不超过10的7次

CF的服务器比较犀利,好像几个忆的计算量都能飘过,也就是暴力,求出序列后用一个nlogn的求最长递增子序列的算法也可以过

复杂度应该是k * 10^7 * log(maxb) . 

下面贴一种树状数组的做法,相当于用树状数组来优化一个n*maxb的dp

http://www.codeforces.com/contest/261/submission/2951761


上述做法虽然考虑了数列的性质,但还有更好的方法。

膜拜了lzqxh的代码后。。。。thinking。。。。

考虑到数列的性质,长度很长(10^7), 但因为最多只有maxb(10^5)个数,所以我们可以考虑这样的状态 , dp[i]表示以i结尾的最长递增子序列的长度,那么如果当前数为a

当前最长的递增子序列的长度为len,那么我们应该找前面比a小的数b,然后判断一下dp[b]+1能否更新dp[a],什么样的长度能更新dp[a]呢,肯定是dp[a]+1喽,所以应该找长度为dp[a]的且小于a的数接上a,而且如果dp[a]==len+1了,就不用再更新了,因为加入一个a最多能使最长递增序列的长度增加1,既然已经增加1了,就不需要再更新了。

最后有一个很巧妙的做法是用一个数组映射一下dp值为x的最后一个数,即 num[dp[x]] = x; 找长度为dp[a]的数的时候只需要用这个数组直接找就好了。稍微想一下就知道为什么了,tmp = num[dp[a]] 记录的肯定是当前长度为dp[a]的数字(结尾)中最小的数了,因为如果前面还有长度为dp[a]的,且数字小于tmp的那么tmp可以接上去从而tmp处的长度就应该更长才对,而不是dp[a] 。每个dp[i]最多增加cnt次cnt是数字的种类数,所以复杂度是cnt*cnt的,由于cnt<=n,且cnt<=maxb,所以cnt*cnt <= n*maxb <=10^7

http://www.codeforces.com/contest/261/submission/2953464


codeforces  261E

题意:初始的时候给你两个数,1 0    一次操作可以给右边的数+1,也可以将左边的数乘上右边的数再放回左边,问你有多少的数x(l<=x<=r)可以出现左边的位置上,要求操作的次数小于等于p。

注意到p <= 100,可以发现x肯定都是由小于等于100的素数组成的。然后就是题目的突破口了,处理出所有的素因子在100以内的数,1e9以内这样的数大概有300 0000个(尼玛这种范围让我怎么想!!),设dp[i]代表第i个数最少经过几次操作可以得到,那么接下去的事情就是枚举右边操作了几次,直接两重循环暴力去更新dp就好了,dp[j]肯定是由a[k] * i  == a[j],这样 的k更新过来,这里k不用去枚举,将所有的数排序之后利用单调性不断地往右移动就好了。

http://www.codeforces.com/contest/261/submission/2958347



总结:这场比赛DP比较多,思维很灵活,一般都是很简单的DP前面覆盖一层不容易看透的描述(我比较水。。) , 也就是在一般的Dp上加点东西,非常考验思维,,


原创粉丝点击