题目链接(洛谷) ## 题目大意
给定常数。对于一个长度为的排列,定义
$ f(a)={{1 i k} {a_i},{2 i k+1} {a_i},,_{n-k+1 i n} {a_i}} $
对于一个长度为的序列,定义其权值为中不同的数的个数。
求对于长度为的排列,它们的之和。
正解
不难发现排列有如下性质:
记的第位为,如果,那么这是的在中最后一次出现。
那么答案就是所有排列中相邻两项不同的个数加上。
当时,长度为的窗口,把第项去掉,加入了项,发现最大值变大,也就意味着第项比第到项都大。

枚举表示产生贡献的那个数,有。
对于区间,我们要从小于的个数中选出个放进去并进行排序,有种方法。
对区间外部的数排序,有种方法。
再钦定长度为的窗口的相对位置,有种选法。
所以这部分为: 同理,当时,答案也是上式。
所以最终答案为:
考场做法
先写出暴搜做法,打表输出和答案,并将同一中的每一项与下面做差:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| n k ans diff 2 1 4 2 2 2 2
3 1 18 8 3 2 10 4 3 3 6
4 1 96 40 4 2 56 20 4 3 36 12 4 4 24
5 1 600 240 5 2 360 120 5 3 240 72 5 4 168 48 5 5 120
|
观察差值的规律:
每一组值中不同值答案之间的比值相同,且每增加,所有差值都乘。
设
则有
所以,对于一个值求解时可以先用到推出到。
又因为可以容易得出和,所以可以通过数组递推出到,并更新出。
用表示,即该值刚被更新出来的时候。
1 2 3 4 5 6 7
| sumc[1] = 2; c[1] = 2; for (int i = 3; i <= n; i++) { sumc[i - 2] *= i + 1; c[i - 1] = f[i] * i - sumc[i - 2] - f[i]; sumc[i - 1] = c[i - 1] + sumc[i - 2]; }
|
接着,让。
1 2 3
| for (int i = 1; i < n; i++) { c[i] *= f[n + 1] / f[i + 2]; }
|
最后直接递推答案即可。
v1.5.2