天天看点

2019.06.01 【NOIP提高组】模拟 A 组

T1:排序+线段树维护。

首先按r从小到大排序。设f[i]表示从i开始最多往后跳多少步,那么当前答案就是f[l~r]的最大值。

然后我们每次后移r时都要维护f。考虑在序列尾新加进来一个a[i],那么设j表示满足a[j]>=a[i]的最大的j(j<=i),则f[j+1~i]都会加1,其他不变。这个很好证。

用线段树维护上述过程就好了。

总结:这题关键在于发现只有j+1~i的f是变化的。

T2:费用流。

连边方式如下:建立源点和汇点,源点向第一行的每一个点连流量为inf,费用为0的边。(用(inf,0)表示,下同)。每一个(i,j)向自己连(1,a[i][j]),再向(i+1,j)和(i+1,j+1)连(1,0)。最后一行向汇点连(inf,0)。第一问做一遍费用流即可。

对于第二问,要把每个(i,j)连向自己的(1,a[i][j])改为(inf,a[i][j])。除此之外,还要建立一个超级源点连向源点,边为(m,0)。这是为了保证路径不超过m条。

总结:

费用流的做法:与最大流相似,不过每次增广时要找费用和最小的增广路径(SPFA),在增广这条路上的最小流量。

T3:

这是一道偏数学的题。

因为关键的一个问题就是处理循环同构的情况,所以设f[d]表示最小循环节长度为d的串的个数。则ans=sum(f[d]/d),因为每一个最小循环节为d的串都可以生成出d个循环同构的串。

接下来的任务就是求f了。设g[d]表示循环节长度为d的串的个数(注意不是“最小”循环节)。则f[d]=g[d]-sum(f[l])(l是d的因数且l<d)。这是因为如果一个串有l这个循环节,那么它一定有d这个循环节,所以用g[d]减去所有f[l]求出的就是最小循环节为d的串的个数。

再加下来的任务就是求g了。设dp[i][j]表示长度为i,首位为1,后j位为0的串的个数。那么转移就是:

dp[i+1][0]+=dp[i][j](j<=k)    dp[i+1][j+1]+=dp[i][j] (j+1<=k)

原理就是讨论在当前长为i的串的最后加一个0还是1.

最后g[d]=sum(f[d][j]*(j+1))。因为每一个串后面都有j个0,每一个0有都可以转到首位,所以总共有(j+1)种情况。

至此,这道就做完了。