【题目描述】
某日,琪露诺写了N封信要装到N个信封里面,却全都装错了……现在想知道有多少种装错的可能性。
【输入描述】
信和信封的数量N。
【输出描述】
装错的可能性的数量。
【样例输入】
输入样例1
2
输入样例2
4
【样例输出】
输出样例1
1
输出样例2
9
【数据范围及提示】
1≤N≤100
简解:
源代码: #include<cstdio> int n,f[101]; int main() { scanf("%d",&n); f[1]=0; f[2]=1; for (int a=3;a<=n;a++) f[a]=(a-1)*(f[a-1]+f[a-2]); //应用了错排公式。 printf("%d",f[n]); //本题还应使用高精度算法,但在此忽略。 return 0; } /* 数论——《错排公式》: f[n]=(n-1)*(f[n-1]+f[n-2]) Step 1: 把第n个元素放在任意的一个位置,例如位置k(除位置n外)。 Step 2: 放置第k个元素无非为以下两种可能: (1)放置在位置n: 则剩下的(n-2)个元素就有f(n-2)种放置方法。 (2)不放置在位置n: 则剩下的(n-2)个元素就有f(n-1)种放置方法。 */
正解:
源代码: #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n,num[101],f[101][3001]; void x1(int t) //单精度 乘 高精度。 { int k(0); for (int a=1;a<=num[t];a++) { k+=f[t][a]*(t-1); f[t][a]=k%10; k/=10; } while (k) //挺值得学习的。 { f[t][++num[t]]=k%10; k/=10; } } void x2(int t1,int t2) //高精度 加 高精度。 { int k(0); num[t1+1]=max(num[t1],num[t2]); for (int a=1;a<=num[t1+1];a++) { k+=f[t1][a]+f[t2][a]; f[t1+1][a]=k%10; k/=10; } while (k) { f[t1+1][++num[t1+1]]=k%10; k/=10; } } int main() { memset(f,0,sizeof(f)); scanf("%d",&n); if (!n) { printf("0"); return 0; } f[1][1]=0; f[2][1]=1; num[1]=num[2]=1; for (int a=3;a<=n;a++) { x2(a-1,a-2); x1(a); } for (int a=num[n];a>0;a--) printf("%d",f[n][a]); return 0; }