序列型DP:⑨要写信
题目描述 Description
琪露诺(冰之妖精)有操控冷气的能力。能瞬间冻结小东西,比普通的妖精更危险。一直在释放冷气的她周围总是非常寒冷。
由于以下三点原因……
- 琪露诺的符卡 冰符“Icicle Fall”-Easy的弹幕有够蠢的,只要站在她的正前方就没任何弹幕会碰到你;
- ZUN在《红魔乡》中介绍她时已经说她有点笨笨的了;
- 在ZUN放出《东方花映冢》的介绍图时,在图中把琪露诺放在了⑨的位置上,并以“⑨笨蛋”简单带过,从此“⑨”及“笨蛋”就成为她的别名了……
所以琪露诺便得到了“笨蛋”的别称。
某日,琪露诺又2了……
她写了N封信要装到N个信封里面,却全都装错了……现在想知道有多少种装错的可能性。
输入描述 Input Description
信和信封的数量N。
输出描述 Output Description
装错的可能性的数量。
分类标签中说这是序列DP,感觉这是组合数学的错排问题
设共有n个元素,数量为Dn
D2=1; D3=2;
假设n排在第k位,k有(n-1)种可能
若k排在n的位置上,剩余有Dn-2种可能
若k不排在n的位置上,那么将第n位重新考虑成一个新的“第k位”,这时的包括k在内的剩下n-1个数的每一种错排,都等价于只有n-1个数时的错排(只是其中的第k位会换成第n位)。其错排数为Dn-1。
所以,Dn=(n-1)*(Dn-1+Dn-2)
//高精度运算
var num1,num2,num:array[1..10000]of integer;
n:longint;
i,j,k,len:longint;
begin readln(n);
num1[1]:=1;
num2[1]:=2;
len:=1;
for j:=4 to n do
begin for i:=1 to len do
num[i]:=num1[i]+num2[i];
for i:=1 to len do
begin num[i+1]:=num[i+1]+num[i] div 10;
num[i]:=num[i] mod 10;
end;
if num[len+1]<>0
then inc(len);
for i:=1 to len do
num[i]:=num[i]*(j-1);
for i:=1 to len do
begin num[i+1]:=num[i+1]+num[i]div 10;
num[i]:=num[i] mod 10;
end;
while num[len+1]<>0 do
inc(len);
num1:=num2;
num2:=num;
end;
for i:=len downto 1 do
write(num[i]);
end.