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;

}

 

 

 

你可能感兴趣的:(Bubble)