2017.08.05【NOIP提高组】模拟赛B组

来源:互联网 发布:为知云笔记使用教程 编辑:程序博客网 时间:2024/06/09 22:47

T1:一道水题,但是比赛时我却爆了0。

只需把k转换成二进制数,再当成三进制数的形式输出。


总结:要记住,二进制转换出来的数组的头实际上是相当于二进制数的尾,而数组的尾相当于二进制数的头。此题要从二进制数的尾开始枚举,也就是从数组的头开始循环。


T2:状压dp。

设f[i][j][k]表示已经选了i个人,选择的状态为j,目前的矛盾数量为k的方案数。

则f[i][j][k]=sum(f[i-1][j-2^(l-1)][k-w])

l表示的是第i次选的人,w表示的是第i次选l新增的矛盾数量。

l很好理解,但是关键就是w怎样求?

我们知道,针对每一个l,如果一个与它存在矛盾关系的人比他先入队,那么l入队的新增的矛盾的个数就要加一。所以我们可以判断一下在当前的j里面有多少个与l有矛盾的人是已选的,发现一个就把w+1,最后便能求出答案。


总结:状压dp一定有一些不合法的状态,所以我们可以通过预处理出所有合法的状态来进行优化,而且这样优化的效率是很高的。


T3:一道很很难分治。

我们可以利用快排的思想,把一个序列分开两半来处理,每一半单独的方案数都很好求,但是关键是如何求两半组合起来的方案数(也就是跨过中点的区间的个数)。

我们把当前区间l,r分为两个区间(l,m)和(m+1,r)(m=(l+r)/2)。

首先,我们先扫一遍(m+1,r)这个区间,记录下这个区间的最大值和最小值的变化(也就是dh所说的那个6 3 2 1和6 7 8),接着对这个区间维护它的最大值、最小值以及最大值最小值的乘积的前缀和。

接着,我们扫一遍m~l,这是在枚举左端点。针对每一个左端点i,我们i~m的最大值为max_l,最小值为min_l,那么我们从刚刚维护的(m+1,r)的最大值的变化中找到一个正好大于max_l,最小值的变化中找一个正好小于min_l的数,例如:

最小值的变化:6 3 2 1

最大值的变化:6 7 8

max_l=7,min_l=3

那么找出来的值就是2和8.

那么我们假设2的位置小于8的位置,则

1、从m+1~2的位置-1这一段的min为min_l=3,max为max_l=7,所以这一段对答案的贡献就是3*7*2的位置到m+1的长度。

2、从2的位置到8的位置-1这一段的max为max_7,min不确定,而我们只需要知道这一段min的和就可以计算对答案的贡献,er我们可以利用前缀和来求这一段min的和。

3、从8的位置到r这一段的min和max都不确定,但我们只需要知道这一段min*max的和就够了,这个我们也可以用前缀和来解决。

那么2的位置大于或者等于8的位置的情况也和上面差不多,只需再讨论一下即可。

这样我们就可以做出这道题了。

原创粉丝点击