您的位置:首页 > 其它

POJ 3761 (组合计数)

2016-07-24 16:23 316 查看

题意:

冒泡排序一轮: 相邻之间的两个数比较, 然后交换。

现在给你一个有序的数列, 从 1 - N;而且是经过 K 轮交换得来的。

问你有多少个这样的数列。

分析:

对于一个数列, 我们是有一个反序表的 Ai, 反序表中的 Ai 表示 i 左边有多少比 i 要大的数的个数。可以很容易得到反序表 和 原序列是一一对应的。
而经过冒泡排序的一轮, 是可以发现把 反序表中大于0 的数都减一的。所以刚好 K 轮冒泡就是其反序表的 Ai 的 Max 是 K。现在就是来设计 反序表了。
反序表的 Ai 值是在 [0, N-i] 的。则 i >= N-k 时, 这些值的设计方案有 (K+1)!种, 当 i < N-K 时, 有 (K+1)^ (N-K-1)种方案, 则共有方案为
K! * (K+1)^(N-K)种, ---最大值是 K 的个数--> F(K) 。
而我们是要求 至少有一个 K 的方案,则可以 F(K)- F(K-1)即可得到答案了。


Code:

//#include <bits/stdc++.h>
#include <iostream>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int maxn = 1e6 + 131;
typedef long long LL;
typedef unsigned long long ULL;
const LL mod = 20100713;
LL KJ[maxn];

LL PowMod(LL a, LL n) {
LL ret = 1;
while(n) {
if(n & 1LL) ret = ret * a % mod;
a = a * a % mod;
n >>= 1;
}
return ret;
}

int main() {
ios::sync_with_stdio(false);
KJ[0] = KJ[1] = 1;
for(int i = 2; i < maxn; ++i)
KJ[i] = KJ[i-1] * i % mod;
int T;
LL n, k;
cin >> T;
while(T--) {
cin >> n >> k;
LL ans = KJ[k];
ans = ans * (PowMod((k+1), n-k) - PowMod(k, n-k) + mod) % mod;
cout << ans << endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  poj 组合数学