uva 11077 排列

#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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值