题目描述 Description
琪露诺(冰之妖精)有操控冷气的能力。能瞬间冻结小东西,比普通的妖精更危险。一直在释放冷气的她周围总是非常寒冷。
由于以下三点原因……
- 琪露诺的符卡 冰符“Icicle Fall”-Easy的弹幕有够蠢的,只要站在她的正前方就没任何弹幕会碰到你;
- ZUN在《红魔乡》中介绍她时已经说她有点笨笨的了;
- 在ZUN放出《东方花映冢》的介绍图时,在图中把琪露诺放在了⑨的位置上,并以“⑨笨蛋”简单带过,从此“⑨”及“笨蛋”就成为她的别名了……
所以琪露诺便得到了“笨蛋”的别称。
某日,琪露诺又2了……
她写了N封信要装到N个信封里面,却全都装错了……现在想知道有多少种装错的可能性。
输入描述 Input Description
信和信封的数量N。
输出描述 Output Description
装错的可能性的数量。
样例输入 Sample Input
输入样例1
2
输入样例2
4
样例输出 Sample Output
输出样例1
1
输出样例2
9
数据范围及提示 Data Size & Hint
1≤N≤100
/* 递推+高精度。第一次得了60分,把b、c数组拿到主函数外面就都过了,长记性了…… 有n封信,第i封信装错的话有i-1种可能,设i-1其中一个为k,那么k有两种装法: ①:装到第i个信封里,此时剩下的i-2封信要装到i-2个信封里,就有f[i-2]; ②:装到除i之外的信封里,这时i-1的作用和i一样,剩下的就有f[i-1]; 综上所述,得到状态转移方程: f[i]=(i-1)*(f[i-1]+f[i-2]) */ #include<cstdio> #include<iostream> #include<cstring> #define M 210 using namespace std; struct node { int a[M],len; };node f[M]; int b[M],c[M]; int main() { int n; scanf("%d",&n); f[1].a[1]=0;f[2].a[1]=1; f[1].len=1;f[2].len=1; for(int i=3;i<=n;i++) { //高精度加法 int lena=f[i-1].len,lenb=f[i-2].len,lenc=1,x=0; while(lenc<=lena||lenc<=lenb) { f[i].a[lenc]=f[i-1].a[lenc]+f[i-2].a[lenc]+x; x=f[i].a[lenc]/10; f[i].a[lenc]%=10; lenc++; } f[i].a[lenc]=x; if(f[i].a[lenc]==0)lenc--; f[i].len=lenc; //高精度乘法 int la=f[i].len,zh=i-1,lb=0; memset(b,0,sizeof(b)); memset(c,0,sizeof(c)); while(zh) { b[++lb]=zh%10; zh/=10; } for(int j=1;j<=la;j++) { int x=0; for(int k=1;k<=lb;k++) { c[j+k-1]+=f[i].a[j]*b[k]+x; x=c[j+k-1]/10; c[j+k-1]%=10; } c[j+lb]=x; } int lc=la+lb; f[i].len=lc; while(c[lc]==0&&lc>1)lc--; for(int j=lc;j>=1;j--) f[i].a[j]=c[j]; } int flag=0; for(int i=f[n].len;i>=1;i--) if(!flag&&!f[n].a[i])continue; else { printf("%d",f[n].a[i]); flag=1; } return 0; }