poj3761 bubble sort

题意:已知N,对N的一个排列进行冒泡排序,共K趟后排成升序,求一共有多少个这样的排列(mod 20100713)。

最开始我沙茶地得出了个结论,一趟就是最大值沉底,其它不变,因此和最长下降子序列有关(其实选择排序应该是这样)。然而实际上不是。每排一趟,一个数的逆序数最多-1(沉底那个除外),因此题目就是让你构造逆序数最多的一个数的逆序数是K的N排列。

设f(i,K)为前i小的数进行排列,其中逆序数最大的一个数的逆序数小于等于K的方案数。当i小于等于K时,显然无法使得任意数的逆序数超过K,故f(i, K) = f(i-1, K) * i;  i>K时,考虑将i放入这个排列,因为i是目前最大一个数,所以要使得i处于最后K+1个位置才能保证在i后面的之前放的数不超过K个。通项易得为f(N, K) = K!*(K+1)^(N-K)。然而这只是最大逆序数小于等于K的方案数,这题最巧妙的地方就是恰好等于K的方案数可以作差求得,为f(N,K)-f(N,K-1)。


#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define LL long long
const LL tsy = 20100713;
const int MAXN = 1000010;
int T;
LL N, K;
LL jc[MAXN];
LL ksm(LL a, LL b)
{
	LL res = 1;
	for (; b>0; b>>=1, a=a*a%tsy)
		if (b&1) res = res * a % tsy;
	return res;
}
inline LL getx(LL n, LL k) {
	return jc[k] * ksm(k+1, n-k) % tsy;
}
int main()
{
	scanf("%d", &T);
	jc[0] = 1;
	for (LL i = 1; i<MAXN; ++i)
		jc[i] = jc[i-1] * i % tsy;
	while (T--) {
		scanf("%I64d%I64d", &N, &K);
		LL ans = (getx(N, K) - getx(N, K-1)) % tsy;
		printf("%I64d\n",  (ans + tsy) % tsy);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值