转载于:http://www.cnblogs.com/767355675hutaishi/p/3873770.html

题目大意:众所周知冒泡排序算法多数情况下不能只扫描一遍就结束排序,而是要扫描好几遍。现在你的任务是求1~N的排列中,需要扫描K遍才能排好序的数列的个数模20100713。注意,不同于真正的冒泡排序算法,只要数列有序就立刻停止,而不用再检验一遍。

估计多数人都是找规律吧,先看出递推,然后求出通项……这个题只有找出通项公式才能通过,所以首先公布答案:

K!((K + 1) ^ (N - K) - K ^ (N - K))

好吧,现在让我们来证明一下。

首先定义函数d(x),对于1~N的一个排列,d(x)表示第x个数前面有多少个数字大于该数。

比如说对于3 2 4 1 5,有d(1) = 0,d(2) = 1,d(3) = 0,d(4) = 3,d(5) = 0。

现在我们来证明d(x)函数的两条性质:

(一)对于一个排列,对于所有x <= N,有d(x) = 0是这个排列是有序的充要条件。

如果存在1 <= i, j <= N,使得i < j,ai > aj,那么由于aj前面有ai大于它,故d(j) >= 1。而这与d(j) = 0矛盾,反之亦然。所以说命题成立。

(二)冒泡排序的每次扫描的结果是,对于非零的d(x)值,这个位置的d(x)会且只会减少1。

考虑某个非零的d(x)值。由于d(x) >= 1,所以必然存在整数i∈[1, x - 1],满足ai > ax。设m为a1, a2, ..., a(x -1)中的最大值,位置为i,则必有m > ax。那么,在扫描到a(x - 1)和ax的时候,由于前面的交换,必然有a(x - 1) = m。

原因是如果前面的交换将m交换到了a(x - 2)的位置,那么由于m > a(x - 1),那么ai必然能够被交换到a(x - 1)的位置。故由数学归纳法,只要m能够被交换到a(i + 1)即可。而在交换之前a(i - 1) < m,m与a(i - 1)不发生交换;同时必然有m > a(i + 1),m一定会被交换到a(i + 1),故该结论成立,从而扫描a(x - 1)和ax的时候a(x - 1) = m。

这时由于m > ax,m与ax之间要交换,交换的效果由于ax前面比ax小的数字减少了一个,d(x)减小了1。所以说d(x)在这个过程中必会减少。

而另一方面,完成了m与ax的这次交换之后,这一次扫描显然就不会再交换ax的值了(这时ax位置上的值已经是m了)。所以说,d(x)也只能减少1。这就证明完毕。

证明了d(x)函数的这个性质之后,我们就可以得出对于1~n的一个排列,它所需要的冒泡排序的扫描次数为

K = max (d(i), 1 <= i <= N)

而这个结论很显然,因为只有经过K次扫描,所有位置的d值才能都变为0。

到此,我们成功地将冒泡排序的次数问题转化为d(x)值满足条件的数列的问题。原问题也就转化成了有多少个排列使得其中最大的d(x)值恰好为K。然而这也是复杂的,所以说我们不妨先解决有多少个排列使得其中最大的d(x)值不大于K。

首先可以确定N >= K + 1,否则不可能出现某个位置前面有K个数大于它。

然后决定原数列中1的位置。显而易见,如果最小数的位置为x,则其d(x) = x - 1。而d(x) <= K,故x <= K + 1,也就是说1有K + 1种放置方法;而放置2的时候,我们完全可以考虑一个新的排列2~N,这时2有K + 1种放置方法,然后再把1插到位置1~K + 1,而不影响其它数的d值。所以说,前N - K个数的放置方法的种类有

(K + 1) ^ (N - K)

之后只需要考虑N - K + 1 ~ N的排列即可。然而,由于整个数列只有K个数字,不可能出现某个d值大于K + 1。所以说排列方法有K!种。故,所有位置d值不大于K的排列的方案数有

K!((K + 1) ^ (N - K))

但是这是不大于K的排列数量,恰好为K的有怎么办呢?很简单,只需要减去不大于K - 1的排列数量便可。所以最后的答案为

K!((K + 1) ^ (N - K)) - (K - 1)!(K ^ (N - K + 1))

化简之后我们就得到

K!((K + 1) ^ (N - K) - K ^ (N - K))

这就是原来的式子,它的正确性就证明完毕。

#include <iostream>
#include <cstdio>
using namespace std; const int Mod=;
__int64 fac[]= {}; __int64 Power(__int64 a,__int64 k)
{
__int64 ret=;
for(; k; k>>=)
{
if(k&) ret=ret*a%Mod;
a=a*a%Mod;
}
return ret;
}
int main()
{
for(int i=; i<; i++)
fac[i]=fac[i-]*i%Mod;
int t;
scanf("%d",&t);
while(t--)
{
int n,k;
scanf("%d%d",&n,&k);
printf("%I64d\n",(Power(k+,n-k)-Power(k,n-k)+Mod)%Mod*fac[k]%Mod); //Power(k+1,n-k)-Power(k,n-k)可能小于零
} return ; }

POJ 3761 Bubble Sort 快速幂取模+组合数学的更多相关文章

  1. POJ 3761 Bubble Sort(乘方取模)

    点我看题目 题意 : 冒泡排序的原理众所周知,需要扫描很多遍.而现在是求1到n的各种排列中,需要扫描k遍就变为有序的数列的个数,结果模20100713,当然了,只要数列有序就扫描结束,不需要像真正的冒 ...

  2. poj 3761 Bubble Sort_快速幂

    题意:问你冒泡排序第i次排序,一共排了多少次 套公式K!((K + 1) ^ (N - K) - K ^ (N - K)) #include <iostream> #include< ...

  3. 快速幂取模 POJ 3761 bubble sort

    题目传送门 /* 题意:求冒泡排序扫描k次能排好序的全排列个数 数学:这里有一个反序列表的概念,bj表示在j左边,但大于j的个数.不多说了,我也是看网上的解题报告. 详细解释:http://blog. ...

  4. 快速幂取模(POJ 1995)

    http://poj.org/problem?id=1995 以这道题来分析一下快速幂取模 a^b%c(这就是著名的RSA公钥的加密方法),当a,b很大时,直接求解这个问题不太可能 利用公式a*b%c ...

  5. POJ 3233-Matrix Power Series( S = A + A^2 + A^3 + … + A^k 矩阵快速幂取模)

    Matrix Power Series Time Limit: 3000MS   Memory Limit: 131072K Total Submissions: 20309   Accepted:  ...

  6. POJ 1845 Sumdiv [素数分解 快速幂取模 二分求和等比数列]

    传送门:http://poj.org/problem?id=1845 大致题意: 求A^B的所有约数(即因子)之和,并对其取模 9901再输出. 解题基础: 1) 整数的唯一分解定理: 任意正整数都有 ...

  7. 【转】C语言快速幂取模算法小结

    (转自:http://www.jb51.net/article/54947.htm) 本文实例汇总了C语言实现的快速幂取模算法,是比较常见的算法.分享给大家供大家参考之用.具体如下: 首先,所谓的快速 ...

  8. HDU 1061 Rightmost Digit --- 快速幂取模

    HDU 1061 题目大意:给定数字n(1<=n<=1,000,000,000),求n^n%10的结果 解题思路:首先n可以很大,直接累积n^n再求模肯定是不可取的, 因为会超出数据范围, ...

  9. UVa 11582 (快速幂取模) Colossal Fibonacci Numbers!

    题意: 斐波那契数列f(0) = 0, f(1) = 1, f(n+2) = f(n+1) + f(n) (n ≥ 0) 输入a.b.n,求f(ab)%n 分析: 构造一个新数列F(i) = f(i) ...

随机推荐

  1. iOS 内存管理机制和循环引用处理方法

    简述 ARC: 自动引用计数, Automatic Reference Counting MRC: Mannul Reference Counting ARC工作原理 1.当每次创建一个新实例时,AR ...

  2. GCC 编译使用动态链接库 LD

    可以把当前路径加入 /etc/ld.so.conf中然后运行ldconfig,或者以当前路径为参数运行ldconfig 2.把当前路径加入环境变量LD_LIBRARY_PATH中3. 如果你觉得不会引 ...

  3. 哈希表用于Key与Value的对应

    一个类的某个属性要实现Key与Value的对应,以便通过访问名称就可以知道对应值,而不是通过索引号,最简单的方法直接用 哈希表using System.Collections;class Class1 ...

  4. 自己做的加速app测试流程的小工具,目前打算开放使用,想注册的朋友抓紧了,嘻嘻

    为了加速小团队app的测试流程做了这个东西,www.xunce.net 主要特性: web: 一键上传app,方便随时下载 备注测试要点 添加附件,如checklist等文档  自动识别app版本,名 ...

  5. uniGUI试用笔记(十三)调用WebService

    今天尝试用uniGUI做Web服务器,调用应用服务器的WebService,遇到些问题记录下来备忘. 1.对WebService的调用同一般App程序,只是注意如果WebService的执行时间较长, ...

  6. cocos在win平台exe无法使用 UserDefault 解决方法

    exe模拟器用来调度cocos本来是很方便的事情,但最近很多win10策划无法调用UserDefault.一直以为是权限问题,今天有空读一下码才发现.原来是cocos的bug.存在本地的UserDef ...

  7. Ubuntu 配置AP总结

    1.这个是使用别人写的一个GUI来配置,:http://hi.baidu.com/lexiangtaotao/item/5d4e87f22db132c70cd1c86f 2.使用hostapd配置:h ...

  8. MDX 占比同比环比

    http://blog.csdn.net/hero_hegang/article/details/9072889

  9. 测试GeoGebra博客

    已知函数 \(\textit{f}(\textit{x})=2\textit{m}\ln\textit{x}-\textit{x}^2\), \(\textit{g}(\textit{x})=\tex ...

  10. androidStudio 改包名

    很多时候,我们需要将app换套皮肤,然后当作一个新的app来打包.如果只是更换了资源这样的安装包会将之前安装好的app替换掉. 1:不推荐的做法:直接在AndroidStudio里修改build.gr ...