题目:https://jzoj.net/senior/#contest/problems/1767
T1:题目大意:指在一个序列里,找出每一个数的右边的数小于他的数的个数,并记录起来。一旦有一个数比它大,则接下来的数都不可计入答案。
解法:很明显,如果暴力O(n²)的话,肯定会超时,所以我们可以用一个栈来优化一下,确保这个栈必须是降序的,然后每次加入一个数就把栈里面所有大于这个数的数删掉,并统计出还在栈里的数有多少个,记录一下即可。
T2:统计出[L..R]区间里每个数转化成2进制数后,'0'的个数>='1'的个数的数有多少个。
这道题目如果用纯粹的暴力求解,只能60分。然而我们可以优化。
在优化之前,我们要明白对于求一个[L..R]区间,只需求出1~R区间的方案数,再减去1~L-1区间内的方案数就等于L~R的方案数了,所以我们只需定义一个函数conut(x),表示1~x的round numbers的数量。
例(当x=46的时候):
46(10)=101110(2)
对于101110这个二进制数,我们如果统计比它位数的少的数的round numbers的数量的话,则,可模拟成如下计算:
5位:1 _ _ _ _ //后面4位显然可以填3个0,4个0,所以方案数就是C(4,3)+C(4,4)
4位:1 _ _ _ //后面3位显然可以填2个0,3个0,所以方案数就是C(3,2)+C(3,3)
3位:1 _ _ //后面2位显然必须填2个0,所以方案数就是C(2,2)
2位:1 _ //后面1位必须填0,所以方案数就是C(1,1)
对于计算时位数比原来x转化成2进制位数小的数,会方便计算很多,但对于位数相等的话,则是不同的情况。
如果位数相同:
第一位必须是1,第二位也必须是0(否则就大于x),第三位则可填0,也可填1,则这是一个特殊的情况:
1 0 1 _ _ _
我们可以这么计算,后面还有3位,可以填2个0,3个0,则方案数是C(3,2)+C(3,3)。
第4位也是1,也可以照上例计算,依次类推,最后可得总方案数。
这其实与数位Dp的思想是类似的,对于每一位他所对应的情况,只不过这里是直接用数学方法求出来。
T3:题目大意:给定一个矩形,要求在'1'的位置种植玉米,且玉米的位置不能相邻(上下左右),问总共有多少种种植玉米的方案数。
很明显是状压DP。如果直接用搜索的话,虽然因为数据水的原因能坑到90分,但是纯粹搜索好像真的没有什么优化了。。接下来讲讲如何状压。
其实这里状压的思路就是把2进制数转化成十进制数,并运用好位运算和进制转化的一些思路来做。再简单地说,就是当前这一行的状态其实是由上一行的状态得来的,我们把上一行的状态看做一个十进制数,而并非一个真正的二进制串,这就是所谓的状态压缩。
例:
4 4
1 0 0 1
1 1 1 0
1 1 0 0
0 1 1 0
如果我们要DP,对于第一行来说他是特殊的,因为他无法根据上一行的状态得来,所以我们可以预处理一下。即从1~1 shl m-1去判断这个十进制数转化成2进制数后,是否能种植——亦即,这个十进制数是1的地方,原来第一行的这个地方也必须是1,如果是0则这个十进制数不可行。
预处理之后,我们在求第2行的时候就可以枚举上一行(i-1)的状态——十进制数(x),再枚举当前第i行的状态——十进制数(y),然后判断这两个十进制数是否符合条件(上下不能相邻——都有'1'),并判断第i行是否能存在这个十进制数(y),如果这2个条件都符合,则可以把f[i,y]累加f[i,x],并mod上10^9,最后输出最大值即可。
T4:给出一个无向图G=(V,E)然后问让你求出节点1到节点n的次短路。
很明显是spfa。
这里介绍两种方法:
第一种:最容易想到的,两遍——spfa(1),spfa(n),求出1到某个点的最短距离,和n到某个点最短距离,然后判断1到x点,与n到x点的距离,然后判断这两个点到x点的距离和是否小于最短路并且比当前的最小值还小则记录下来,最后输出咯。
第二种:1遍spfa。
我们知道点x到点a[x,i]只有相对应的4种情况——
dis1[a[x,i]],dis2[a[x,i]],dis1[x]+b[x,i],dis2[x]+b[x,i]
这4种请况的最小值明显就是dis1[a[x,i]]的值了,而次小值则是这4个数当中次小的值(次小肯定不能与最小值相等)
然后更新完最小值后,如果这两者之间的某一个值被更新了,都要把a[x,i]放进队列,不然的话就求不到最短距离和次短距离(重点)