【题解】P7322 「PMOI-4」排列变换

题目链接(洛谷) ## 题目大意

给定常数k。对于一个长度为n排列a,定义

$ f(a)={{1 i k} {a_i},{2 i k+1} {a_i},,_{n-k+1 i n} {a_i}} $

对于一个长度为n序列a,定义其权值w(a)a中不同的数的个数。

求对于长度为n的排列p,它们的w(f(p))之和。

1kn5×105

正解

不难发现排列有如下性质:

f(a)的第i位为f(a)i,如果f(a)if(a)i+1,那么这是f(a)i的在f(a)中最后一次出现。

那么答案就是所有排列中相邻两项不同的个数加上n!

f(a)i1<f(a)i时,长度为k的窗口,把第ik项去掉,加入了i项,发现最大值变大,也就意味着第i项比第i1ik项都大。

枚举i表示产生贡献的那个数,有i=k+1n()

对于区间[ik,i1],我们要从小于ii1个数中选出k个放进去并进行排序,有Ai1k种方法。

对区间外部的数排序,有(nk1)!种方法。

再钦定长度为k+1的窗口的相对位置,有nk种选法。

所以这部分为: i=k+1nAi1k(nk1)!(nk) 同理,当f(a)i1>f(a)i时,答案也是上式。

所以最终答案为: n!+2×i=k+1nAi1k(nk1)!(nk)

考场做法

先写出暴搜做法,打表输出n,k和答案,并将同一n中的每一项与下面做差:

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

观察差值的规律:

每一组n值中不同k值答案之间的比值相同,且n每增加1,所有差值都乘n+1

diffi,j=ansi,jansi,j+1,i>j 则有

diffi,j=diffi1,j×(i+1)

所以,对于一个n值求解时可以先用diffn1,1diffn1,n2推出diffn,1diffn,n2

又因为可以容易得出ansn,1=n!nansn,n=n!,所以可以通过diff数组递推出ansn,1ansn,n1,并更新出diffn,n1=ansn,n1ansn,n

ci表示diffi+1,i,即该值刚被更新出来的时候。

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; //sumc是c的前缀和
c[i - 1] = f[i] * i - sumc[i - 2] - f[i]; //f[i]表示i的阶乘
sumc[i - 1] = c[i - 1] + sumc[i - 2];
}

接着,让ci=diff(n,i)

1
2
3
for (int i = 1; i < n; i++) {
c[i] *= f[n + 1] / f[i + 2];
}

最后直接O(n)递推答案即可。