题目大意:这是一道简单排列组合题 。简单说下题意:n件物品,把这n件物品放到不是原来的位置,问所有的方案数。所有的位置都没有变。
题目解析:按照高中的方法,很快得到一个递推公式:f [n]= (n-1)*( f [n-1] + f [n-2] ) 。这个公式也不难理解,可以采取这样的策咯:一件物品一件物品的放,则第一件物品,假设编号1,有n-1个位置可放,假如放到原来物品 2 的位置,则再放物品 2,依次进行下去......也就是放到的位置上原来是哪个物品则下一个就放该物品 。按照这种策咯,放第一件物品时,有n-1种选择,还是假如放到了2号物品原来的位置,那么,就放2号物品,2号物品的选择有两类,一类是物品 1 的原来位置(这类中有且只有一个位置),另一类不是物品 1 的原来位置,选择了前一类方位置时,第二步有 f(n-2)种方案,当选择第二类位置时相当于有 f(n-1) 种方案 。根据加法原理,第二步有 f(n-2)+f(n-1)种方案,根据乘法原理总共有 (n-1)*(f(n-2)+f(n-1)) 方案 。
注意:最后的结果比较坑,要用到高精度,不过,下文代码中的高精度不是按10进制的高精度写的,而是按10^6进制的高精度写的 。
代码如下:
1 # include<iostream> 2 # include<cstdio> 3 # include<cstring> 4 # include<algorithm> 5 using namespace std; 6 const int N=1000000; 7 int ans[805][550]; 8 void init() 9 { 10 memset(ans,0,sizeof(0)); 11 ans[1][0]=ans[2][0]=1; 12 ans[1][1]=0,ans[2][1]=1; 13 for(int i=3;i<=800;++i){ 14 for(int j=1;j<=ans[i-1][0];++j){ 15 ans[i][j]+=(i-1)*(ans[i-1][j]+ans[i-2][j]); 16 ans[i][j+1]+=(ans[i][j]/N); 17 ans[i][j]%=N; 18 } 19 for(int j=ans[i-1][0];;++j){ 20 if(!ans[i][j]) 21 break; 22 ans[i][0]=j; 23 } 24 } 25 } 26 int main() 27 { 28 init(); 29 int n; 30 while(scanf("%d",&n)) 31 { 32 if(n==-1) 33 break; 34 if(n==1){ 35 printf("0 "); 36 continue; 37 } 38 for(int i=ans[n][0];i>=1;--i){ 39 if(i==ans[n][0]&&ans[n][i]) 40 printf("%d",ans[n][i]); 41 else 42 printf("%06d",ans[n][i]); 43 } 44 printf(" "); 45 } 46 return 0; 47 }