#include<cstdio>
#include<cstring>
const int maxn = 30;
unsigned long long f[maxn][maxn];
int main() {
memset(f, 0, sizeof(f));
f[1][0] = 1;
for(int i = 2; i <= 21; i++)
for(int j = 0; j < i; j++) {
f[i][j] = f[i-1][j];
if(j > 0) f[i][j] += f[i-1][j-1] * (i-1);
}
int n, k;
while(scanf("%d%d", &n, &k) == 2 && n)
printf("%llu\n", f[n][k]);
return 0;
}
每个长度为n循环需要交换n-1次才能将交换到对应的位置,例如1->2,2->4,4->1,(1,2,4)位置上对应值为(2,4,1)
相当于一个长度为3的环逆时针旋转了1格,要变换回来,需要跟原位置交换,因为成环,所以共n-1次
那么对于序列P,有x个循环节,长度为n,就需要交换n-x次
对于f[i][j],表示交换j次能变为1~i的序列的种数
我们找到递推式:f[i][j]=f[i-1][j]+f[i-1][j-1]*(i-1),边界是f[1][0]=1,其余为0
解释:新增的i,如果与自己构成循环,那么循环数和长度都加一,交换数不变,所以是f[i-1][j]
新增的i,如果参加到其他环中,每个数后一种,共i-1种,循环数不变,长度加一,所以是f[i-1][j-1]*(i-1)
例如1->2,2->3,3->1,{2,3,1};将4添加到1后就是1->4,4->2,2->3,3->1,序列为{4,3,1,2};其他同上
题解来自于 http://blog.csdn.net/a601025382s/article/details/9818717