Uva-11077(Find the Permutations-排列统计)(斯特林数+Dp)

18 篇文章 0 订阅
8 篇文章 0 订阅

题目

vjudge传送门
Uva传送门

题目大意:

给出 1~n 的排列,可以通过一系列的交换成{1,2,3,…,n}
给定 n,k 求统计有多少个排列至少需要交换k次才能变成{1,2,3,…,n}

数据范围

1 ≤ n ≤ 21 , 0 ≤ k &lt; n 1\le n\le 21,0\le k&lt;n 1n21,0k<n

思路

我们首先记 P P P 为排列 1 , 2 , 3 , . . . , n {1,2,3,...,n} 1,2,3,...,n

我们可以考虑假设现在有一个排列,要求至少交换多少次变成 P P P ?
首先知道每次交换必定为让一个数归位,人品好的时候会一下子归位两个
然后我们可以将位置有关联的分成一个个循环,各循环之间相互独立

然后又知道两个数为一循环需要交换1次,三个数为一循环需要交换2次,…,两个数为一循环需要交换1次,m个数为一循环需要交换m-1次
相当于这个排列有 x x x 个循环,那么就要交换 n − x n-x nx
那么现在我们知道 交换 k k k 次,那么有 n − k n-k nk 个循环

n 个 数 分 成 m 个 圆 排 列 求 方 案 数 是 不 是 就 是 S 1 n个数分成m个圆排列求方案数是不是就是S1 nmS1?
第一类斯特林数自己百度一下吧

代码

#include<set>
#include<map>
#include<stack>
#include<cmath>
#include<ctime>
#include<queue>
#include<cstdio>
#include<vector>
#include<climits>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define ULL unsigned long long
int read(){
    int f=1,x=0;char c=getchar();
    while(c<'0'||'9'<c){if(c=='-')f=-1;c=getchar();}
    while('0'<=c&&c<='9') x=(x<<3)+(x<<1)+c-'0',c=getchar();
    return f*x;
}
#define MAXN 21
ULL f[MAXN+5][MAXN+5];
int main(){
	memset(f,0,sizeof(f));
	f[1][1]=1;
	for(int i=2;i<=MAXN;i++)
		for(int j=1;j<=i;j++)
			f[i][j]=f[i-1][j-1]+f[i-1][j]*(i-1);
	int n,k;
	while(~scanf("%d %d",&n,&k)&&(n+k))
		printf("%llu\n",f[n][n-k]);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值