poj 3761 Bubble Sort

问题描述如下:

一个具有n个元素的排列,经过kbubble sort排到有序状态。求出满足此条件的排列个数。

首先,了解反序表的概念。《计算机程序设计艺术》第三卷5.1.1反序部分有说明。简述如下:a1,a2,...,an是集合{1,2,...,n}的一个排列。令bj为位于j左边但是大于j的元素个数,就能得到排列a1,a2,...,an的反序表b1,b2,...,b3。比如说:排列

5 9 1 8 2 6 4 7 3

有反序表

位置:  1  2  3  4  5  6  7  8  9

b       2  3  6  4  0  2  2  1  0 

不管什么样子的排列,只要可以比较大小,就可以映射到集合{1,2,...,n}上的一个排列。不难发现,每一趟bubble sort ,都会将这一趟之前反序数大于0的元素的反序数减1。经过k趟之后,所有元素的反序数均为0,也就是说,反序表为n0,亦即有序状态。因此,题目可以演化为,n个元素的排列,反序表中最大值为k,求这样的排列有多少种。

易知,第i个元素的反序数取值范围是[0,n-i],还注意到一个事实,就是:每个元素的反序数取值是相互独立。为什么呢?事实上我开始以为是不独立的,但是验证了几个例子以后,我推翻自己的想法。当然这只是直觉上的。但是可以从《计算机程序设计艺术》第三卷反序部分得到一点理论支撑。引用书上的话一张反序表唯一的确定一个排列(我没有细看这个事实的证明)。因此,反序表和排列之间一一对应。全排列个数是n!,因此反序表的个数也是n!,这只有在取值相互独立的情况下得到。

回到题目,反序数最大为k。那么当n-i<=k,即i>=n-k的时候,元素i可随意放。因为不管怎么放,他们的反序数都不会大于k,取值的个数由i来决定。当i<n-k时候,这些元素的反序数只可以在[0,k]之间选择。这样,我把n个元素分为两类来讨论,前面一类元素有k+1(即i = 1~k+1)个,后面一类有n-k-1(即i=n-k-1~n)个元素。先考虑前面一种情况,我们对前面k+1个元素进行全排列,他们的反序数一定在0~k之间,那么就有(k+1)!种排序的方法。后面一类,我们可以与前面的元素进行对调,但是他们的值之差不能超过k(我们要保证他们的反序数在0~k之间)那么有(k+1)种选择去对调,因此有(k+1^n-k-1种方案。由乘法定理,易得k!*(k+1)^(n-k)

但是,这不是最终答案。上面的结果,只是说经过不超过k趟排到有序状态。并不符合题意。因此,必须保证有一个元素的反序数为k。最好的做法就是计算出不超过k-1趟就排到有序状态的排列数,减掉。很容易利用刚才的结论,得到不超过k-1趟就排到有序状态的排列数为:(k-1)!*(k)^(n-k+1)。两者想减,即得到结果:

k!*((k + 1)^(n - k) - k ^(n - k))

 

View Code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#include<cstring>
#include<vector>
#include<string>
#define LL long long
#define MOD 20100713
using namespace std;
LL A[1000024];
void Init(  )
{
    A[0] = 1LL;
    for( LL i = 1 ; i <= 1000000LL; i++ )
         A[i] = ( i * A[i-1] )%MOD;    
}
LL Pow( LL n,LL a )
{
   LL ans = 1;
   while( n )
   {
       if( n&1 ) ans = (ans*a)%MOD;
       a = (a*a)%MOD;
       n >>= 1;        
   }    
   return ans;
}
int main(  )
{
    int T;
    LL n,k;
    Init();
    while( scanf( "%d",&T )==1 )
    {
        while( T-- )
        {
              scanf( "%I64d %I64d",&n,&k );    
              LL ans = (Pow( n-k , k+1 ) - Pow( n - k , k )+MOD)%MOD;
              printf( "%I64d\n",(ans*A[k])%MOD );
        }    
    }
    //system( "pause" );
    return 0;
}

 

 

 

posted @ 2012-08-13 16:19  wutaoKeen  阅读(226)  评论(0)    收藏  举报