POJ 3761 (组合计数)

题意:

冒泡排序一轮: 相邻之间的两个数比较, 然后交换。
现在给你一个有序的数列, 从 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值