http://codeforces.com/gym/100956
ICPCCamp 2016 Day 6 - Spb SU and Spb AU Contest(Greedy Game-贪心)
题意:给你n个东西,每个东西有两个关键字a,b,第一个人按照关键字a的大小取,每次取a最大的,a相同情况下随意,然后第二个人最坏情况下保证能取到的东西的关键字b的总和是多少?
题解:这题开头想想应该是个贪心,但是不是很好贪,dp是反正做不了
可以先考虑第一个人怎么取,第一个人是一隔一的取,然后第二个人就是取了所有的偶数位,但是这样并不是最优的,但是第一个人对于每个位置n,必须取了大于等于一半的东西,所以可以把第二个人偶数位上取得,前面比较小的,去换后面奇数位比较大的值,然后这样换就能得到最优
不是很好表达,随意YY下
用优先队列维护呢。
AC代码:http://paste.ubuntu.net/15803999/
ICPCCamp 2016 Day 6 - Spb SU and Spb AU Contest(Sort It!-dp+树状数组+组合数学)
题意:题目挺烦的,让你求的东西就是这个排列里面有多少个上升子序列,然后只用这些上升自序列里面的值,去构造一个长度为n的串,一共有多少种方法
题解:求多少个上升自序列就是dp+树状数组咯,很容易,就是用这些值去构造n的串,就等价于用m个值,可以重复出现的去构造长度n的串,然后想了下应该是组合数学里的方法,各种递推都不太好使,于是发现应该用A[i]表示构造长度n的串,用i种值的方法,然后求A[i]=i^n-C[i][i-1]*A[i-1]-C[i][i-2]*A[i-2]-....-C[i][1]*A[1],先处理出来组合数,然后n^2的递推就能求出A[i]了。
然后每次dp之后,加上dp[i][j]*A[j]就行了
AC代码:http://paste.ubuntu.net/15804384/
还有个题明天再补把,也是姿势满满
http://codeforces.com/contest/611/problem/D (dp+lcp预处理)
题意:给你一个长度为n的数字串,然后让你分割成几段,分割开得到的那些数字,是严格上升的并且没有前导0,问你有多少种分割的方法
题解:首先考虑分割,感觉是用dp,dp[i][j]表示结尾是第i位,然后切小于等于j个长度,然后这样切割的方法个数
然后你就往前切j个数字,然后再往前切j个数字,只要比较前面这j个组成的和后面这j个哪个大,如果后面的大就dp[i][j]+=dp[i-j][j],否则就是dp[i][j]+=dp[i-j][j-1]。
每次循环的时候dp[i][j]+=dp[i][j-1]。然后就是考虑前导0的细节了,如果i位或者i-j+1位或者i-2j+1位有0,需要分类考虑一下情况,然后如果i-2j+1<0的话,就要dp[i][j]+=dp[i-j][i-j+1],然后一些细节的地方注意下,这个转移就好叻、
然后就是前j位和后j位的比较大小了,如果直接比较的话,就是n^3的复杂度了,肯定不行,所以需要预处理,然后想到就是i和i-j这两个后缀的lcp,可以用后缀数组解决,但是后缀数组太麻烦了,加上串只有5000,所以可以使用n^2的递推啊,枚举i,j,if(s[i]==s[j]) lcp[i][j]=lcp[i+1][j+1]+1;
AC代码:http://paste.ubuntu.net/15810205/
http://acm.hdu.edu.cn/showproblem.php?pid=5289 (two pointer)
题意:给你n个数字,然后问你有多少个区间,区间里最大最小差小于k
题解:two pointer经典题,左右两端扫一遍,维护set维护里面的最大最小,map维护里面的每个数字出现过几次
AC代码:http://paste.ubuntu.net/15811094/
http://acm.hdu.edu.cn/showproblem.php?pid=5288 (求贡献,预处理+set二分)
题意:给你一个数组,然后里面有10W元素,大小1-10000,给你一个公式,公式的意思是,区间内不被其他数整除的数的个数,然后对所有区间的这个值求和
题解:想到元素的值才1W,就果断给1-10000的数字都打表,处理因子,然后给数字排序,记录每个元素在原来数组里面的坐标,然后所有的坐标都扔进对应的set里,比如1的坐标就扔进s[1]里。
然后考虑每个元素对答案的贡献把,就是考虑这个元素在多少个区间内,不被区间里的其他数字整除,那么就和单调栈类似,考虑左边和右边最远能到达的,都不是他的因子的距离,然后就是枚举他的因子,去对应的set里面找,然后找到他的坐标两边的左边,然后距离相乘求和。
为了方便计算,考虑每个元素的时候,先把他的坐标在对应的set里面删除,然后计算完毕之后再放回去,STL的运算有点多,要防止迭代器指向不对的地方。
AC代码:http://paste.ubuntu.net/15828708/
http://codeforces.com/contest/660/problem/E (组合数学+公式推导)
题意:给你一个长度n的数组a,由1-m的元素构成,问你所有a的里面的不同的子串(可以不连续)的和
题解:空串额外加,考虑长度为k的子串,为了防止重复考虑,所以只考虑这个子串在每个串里面第一次出现的位置,假设k个数字出现的位置是x1,x2....xk,于是1-x1的位置里面的值都不能和x1相同,所以都是m-1种方法,x2到xk之间都是这么考虑,然后xk后面,就随便取,每个位置都是m个取值。
于是就得到了公式
然后对这个公式进行化简,因为里面j每次都在变,不好对组合数求和,所以把两个求和符号换个位置,j在外面枚举,k在里面枚举,然后就能得到一个二项式定理的展开,得到
sigma (m^(j+1)*(2m-1)^(n-j-1)) ,0<=j 最后加上m^n就好了 我感觉这题还是很难的,主要是前面那个考虑的思想,如何不重复计数,是需要多学习的 AC代码:http://paste.ubuntu.net/15828989/