一道超级数学题......

题目如有雷同,纯属巧合......

 

 

 

MTOI

【问题描述】

MT刚接触到了冒泡排序的时候,觉得这个东西太慢了,但是加上break的效果怎么样呢?于是他开始考虑这样一个问题:任意一个N的排列中,有多少种需要恰好扫K次才能使得数列从小到大排列。所谓扫就是第一重循环,当数列有序后程序会自动退出循环。

冒泡排序代码:

Var

 a:array[0..n] of longint;

For i:=1 to n-1 do

  For j:=n downto i+1 do

If a[j]<a[j-1] then

  Swap(a[j],a[j-1]);

【输入格式】

第一行一个数T,表示数据组数

接下来T行,每行两个整数N,K

【输出格式】

T个数,表示答案mod 1000000007

【样例输入】

3

    3 0

    3 1

    3 2

 

【样例输出】

    1

    3

    2

 

【数据说明】

30%T<=10N<=7

100%T ≤ 100,000

1 ≤ N ≤ 1,000,000, 0 ≤ K  N – 1

 

 

我一开始以为是动规,结果花了20分钟打表,30分钟找规律,然后打了个40分的动规(当时居然不准重测,说了空间是512M结果只允许128M,我就全超了,该空间可以对40分......),后来有位神牛打了一份解题报告(没看懂,复制了下来):

 

公式:

K!((K + 1) ^ (N - K) - K ^ (N - K))

好吧,现在让我们来证明一下。

首先,冒泡的两种写法对答案是没有影响的。

一:

Var

 a:array[0..n] of longint;

For i:=1 to n-1 do

  For j:=n downto i+1 do

If a[j]<a[j-1] then

  Swap(a[j],a[j-1]);

 

二:

Var

 a:array[0..n] of longint;

For i:=n-1 downto 1 do

  For j:=1 to i do

If a[j]>a[j+1] then

Swap(a[j],a[j+1]);

为方便叙述,这里根据第二种写法讨论,

首先定义函数d(x),对于1~N的一个排列,d(x)表示x个数位置)前面有多少个数字大于该数。(对应到第一种写法就是第x个数后面有多少个数小于该数,因此两问题是一样的)

比如说对于3 2 4 1 5,有d(1) = 0d(2) = 1d(3) = 0d(4) = 3d(5) = 0

现在我们来证明d(x)函数的两条性质:

(一)对于一个排列,对于所有x <= N,有d(x) = 0是这个排列是有序的充要条件。

(二)冒泡排序的每次扫描的结果是,对于非零的d(x)值,这个位置的d(x)会且只会减少1

我们得出对于1~n的一个排列,它所需要的冒泡排序的扫描次数为

K = max (d(i), 1 <= i <= N)

而这个结论很显然,因为只有经过K次扫描,所有位置的d值才能都变为0

到此,我们成功地将冒泡排序的次数问题转化为d(x)值满足条件的数列的问题。原问题也就转化成了有多少个排列使得其中最大的d(x)值恰好为K。然而这也是复杂的,所以说我们不妨先解决有多少个排列使得其中最大的d(x)值不大于K

首先可以确定N >= K + 1,否则不可能出现某个位置前面有K个数大于它。

然后决定原数列中1的位置。显而易见,如果最小数的位置为x,则其d(x) = x - 1。而d(x) <= K,故x <= K + 1,也就是说1K + 1种放置方法;而放置2的时候,我们完全可以考虑一个新的排列2~N,这时2K + 1种放置方法,然后再把1插到位置1~K + 1,而不影响其它数的d值。所以说,前N - K个数的放置方法的种类有

(K + 1) ^ (N - K)

之后只需要考虑N - K + 1 ~ N的排列即可。然而,由于整个数列只有K个数字,不可能出现某个d值大于K + 1。所以说排列方法有K!种。故,所有位置d值不大于K的排列的方案数有

K!((K + 1) ^ (N - K))

但是这是不大于K的排列数量,恰好为K的有怎么办呢?很简单,只需要减去不大于K - 1的排列数量便可。所以最后的答案为

K!((K + 1) ^ (N - K)) - (K - 1)!(K ^ (N - K + 1))

化简之后我们就得到

K!((K + 1) ^ (N - K) - K ^ (N - K))

这就是原来的式子,它的正确性就证明完毕。

 

 

 

以上为引用 ,然后快速幂就做出来了......

 

 

动规如下(N*K):

 

 

 

 

 

数学归纳法:

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章