【蓝桥杯】冒泡排序

题目:


简化题意:即有n个不同元素的排列恰好经过k趟冒泡排序变得有序,问这样的排列有几种?

*恰好经过k趟变有序的排列有几种有点难求,我们算经过k趟排序就一定能变有序的排列有几种,那么有:f(k) = g(k) - g(k-1)(f(k)为恰好经过k趟冒泡排序才变有序的排列种数,g(k)为经过k趟冒泡排序一定能变有序的排列种数)
冒泡排序的第i趟让数组中第i大的数沉底,那么经过k趟排序,第1大,第2大…一直到第k大的数已经去到后面,所以后面的k个位置是可以任意放元素的,那么假设已经排好了前面的数字,剩下后面的k个位置没有排好那么就是k!(这里为什么不可以是A(n,k),就是先排后面的位置,再排前面的位置?因为后面的位置不是什么元素都可以放的,例如当k < n的时候最后一位是不可以放1的,经过k趟排序,1是不可能上升到第一位的)所以需要先排好前面的元素再排后面的k位,即先放好位置[1,n - k],即元素1到n-k的位置不可以乱放,元素1可以放的位置是下标1到k,2可以放的位置是1到k+1,…就是(k+1)^(n-k),那么可得 g(k) = k! * (k+1)^(n-k),g(k-1)就等于(k-1)! * k^(n-k+1),那么f(k) = g(k)-g(k-1) = k! k! * (k+1)^(n-k) - (k-1)!*k^(n-k)*k = k! * [(k+1)^ (n-k) - k^ (n-k)],预处理一下阶乘的结果直接求解即可``

#include <cstdio>
#include <iostream>
using namespace std;
const int mod = 20100713;
typedef long long ll;
const int N = 1e6+10;
ll f[N];//k!
ll quick(ll a,ll n){
	ll ans = 1;
	while(n){
		if(n&1) ans = (ans*a)%mod;
		a = (a*a)%mod;
		n>>=1;
	}
	return ans;
} 
//预处理k! 
void init(){
	f[0] = f[1] = 1;
	for(int i = 2;i <= N-10;i++){
		f[i] = (f[i-1]*i)%mod;
	}
}
int main(){
	init();
	int t;scanf("%d",&t);
	ll n,k;
	while(t--){
		scanf("%lld%lld",&n,&k);
		ll ans = (f[k]*(quick(k+1,n-k)-quick(k,n-k)+mod)%mod)%mod;
		printf("%lld\n",ans);
	}
	return 0;
}
发布了27 篇原创文章 · 获赞 0 · 访问量 337

猜你喜欢

转载自blog.csdn.net/weixin_44083561/article/details/103749843