博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
poj3761(反序表)
阅读量:7037 次
发布时间:2019-06-28

本文共 1445 字,大约阅读时间需要 4 分钟。

题目链接:https://vjudge.net/problem/POJ-3761

题意:给出n和k,求通过k趟冒泡排序得到长为n的有序排列(元素为n个不同的数)的原排列有多少个。

思路:

先给出反序表的定义:

  令bi(1<=i<=n)為位於i左邊但是大於i的元素個數,就能得到排列a1,a2,...,an的反序表b1,b2,...,b3。比如說,排列5 9 1 8 2 6 4 7 3有反序表2 3 6 4 0 2 2 1 0(在1左邊且大於1的有2個,在2左邊且大於2的有3個,……)。

再给出反序表的重要结论:

  第1個元素的反序數取值範圍是[0,n-1],第i個元素的反序數取值範圍是[0,n-i],最後一個元素的反序數只能是0。并且每個反序數可以在區間內任意取值而不用考慮其他反序數的值,也就是說反序數是相互獨立的。(因为第一个元素的反序数[0,n-1]分别对应n个位置中的一个位置,确定之后去掉这个位置,剩下n-1个位置; 第二个元素的反序数[0,n-1]对应这n-1个位置中的一个,确定之后去掉这个位置,剩下n-2个位置......这样可以得到所有反序表对应的原排列有n!个,原排列本身最多只有n!个,所以反序表和原排列是一一对应的,且反序表中反序数相互独立。)

回到题目:

  不难发现每一趟冒泡排序都会将剩下的>0的反序数减一,所以题目就转变乘最大反序数为k的反序表个数。所以我们可以通过求最大反序数<=k的反序表的个数,元素i的反序数为n-i,令n-i<=k得i>=n-k,即>=n-k的元素其反序数恒<=k,所以其反序数的值可以是其范围内的任意值,共有(k+1)!种可能。对于i<n-k,其反序数范围为[0,k],即k+1种,则共有(k+1)^(n-k-1)种可能。两者相乘得k!*(k+1)^(n-k)。

  同理求出最大反序数<=k-1的个数,相减得k!*[(k+1)^(n-k)-k^(n-k)]。

  然后打表阶乘,利用快速幂取模即可。

AC代码:

#include
using namespace std;typedef long long LL;const int maxn=1000005;const int Mod=20100713;int T;LL f1[maxn];void init(){ f1[0]=f1[1]=1; for(int i=2;i<=1000000;++i) f1[i]=f1[i-1]*i%Mod;}LL qpow(LL a,LL b){ LL ans=1; while(b){ if(b&1) ans=(ans*a)%Mod; a=(a*a)%Mod; b>>=1; } return ans;}int main(){ init(); scanf("%d",&T); while(T--){ LL n,k; scanf("%lld%lld",&n,&k); printf("%lld\n",f1[k]*(qpow(k+1,n-k)-qpow(k,n-k)+1LL*Mod)%Mod); } return 0;}

 

 

 

转载于:https://www.cnblogs.com/FrankChen831X/p/10809243.html

你可能感兴趣的文章
动态代理的几种方式
查看>>
Collections常用方法总结
查看>>
微信小程序
查看>>
bash变量
查看>>
知识点049-supervisor
查看>>
干货满满,Android热修复方案介绍
查看>>
罗振宇跨年演讲之夜 阿里云护航得到App
查看>>
django中间键
查看>>
2017/09/22脚本练习
查看>>
Java通过几种经典的算法来实现数组排序
查看>>
Linux下安装apache可能遇到的问题总结
查看>>
linux下c/c++混合编程
查看>>
FastCGI和CGI运行差异知识普及
查看>>
Spring Boot整合MyBatis学习总结
查看>>
我的友情链接
查看>>
yum仓库搭建
查看>>
一张图告诉你,只会JavaScript还不够!
查看>>
IBM TSM注册许可证
查看>>
WINDOWS SERVER 2003本地管理员、目录服务还原模式管理员、域管理员密码的破解汇总...
查看>>
Lync Server 2013企业版部署系列之九:前端部署后续工作
查看>>