1. 题目
3.Valentine’s Present(prt)
描述
今天是情人节,小杉已经想好了要给喜欢的人送一份特殊的情人节礼物。
礼物是n个颜色各异的箱子,每个箱子里装一个蛋糕,蛋糕是可以上色的。
一个可爱的上色方案应该满足如下条件:
1. 任意一个蛋糕上的颜色应与一个箱子相同(可以是装它的那个箱子的颜色)。
2. 任意开启一个箱子,按里面蛋糕的颜色打开对应的箱子,这两个箱子(也可以是同一个)里的蛋糕颜色相同。
小杉现在想知道总共有多少种可爱的上色方案。
输入格式
一行一个整数n(1<=n<=25)
输出格式
仅有一行,一个整数,为上色方案数对19900801取模的结果
样例输入
2
样例输出
3
样例解释
假设两个箱子一黑一白,可爱的上色方案有如下三种(箱子颜色→蛋糕颜色):
1.黑→黑,白→白
2.黑→白,白→白
3.黑→黑,白→黑
2. 题目实质
其实,这是一道数学函数题。
3. 算法
抽象出模型,令集合 A={1,2,3..n} , f(x):A→A 。求满足 f(f(x))=f(x) 的函数个数。
讨论值域有 k 个数的情况,则 f(f(x))=f(x) 等价于值域中的 k 个数作为定义域时对应的函数值为他们本身,下面简单证明。
令 f(x)=t ,则 t 属于 f(x) 的值域,原式化为 f(t)=t ,等价于值域中的 k 个数作为定义域时对应的函数值为他们本身。
接下来就简单了,值域有k个数的情况数应为 C(n,k)*(n-k)^k (从 n 个数中选取 k个作为值域,剩下的 n-k 个数对应 k 个值域中的任一个,这个是组合数的基本性质) 。特殊的,当值域有 n 个数时,有一个函数满足 (f(x)=x) ,这不符合上式。
故结果为 sum{C(n,k)*k^(n-k)}(k=1..n-1)+1 。
简单来说,如果盒子的编号等于蛋糕的编号的有 k 个(挑 k 个盒子 C(n,k) ),那么剩余 n-k 个可以随便排,所以是 k^(n-k)。
4. 注意事项
其实,注意 n 的范围,大家可以向绝恋LOVE枫那样爆搜,然后打表,一样可以 AC。
某位大牛说的话对,几个小时的机器时间,一定不能让他闲着。
5. 程序代码
先是绝恋LOVE枫的打表程序 (pascal)
program prt(input,output);
var
n : longint;
a:array[1..25] of int64=(0,
3,
416,
4162,
15626,
45611,
45161,
456416,
5214621,
4646646,
18210094,
18023490,
54616166,
10525075,
19427821,
7368914,
4516164,
8297917,
5461617,
4646116,
2500001,
2550675,
7807367,
4652622,
8548517
);
begin
assign(input,'prt.in');reset(input);
assign(output,'prt.out');rewrite(output);
readln(n);
writeln(a[n]);
close(input);
close(output);
end.
再是 SueMiller 的公式程序(pascal)
var ans:int64;
n,k:integer;
i,j:integer;
function C(m,n:integer):integer;
var
ans,i:integer;
begin
ans:=1;
for i:=1 to m do
begin
ans:=ans*n mod 19900801;
n:=n-1;
end;
for i:=1 to m do ans:=ans div i mod 19900801;
C:=ans;
end;
function pow(x,y:int64):int64;
var p,ans:int64;
begin
p:=1;
ans:=x;
repeat
inc(p);
ans:=ans*x mod 19900801;
until p>=y;
end;
begin
assign(input,'prt.in');reset(input);
assign(output,'prt.out');rewrite(output);
readln(n);
ans:=0;
for k:=1 to n-1 do
ans:=(ans+C(k,n)* pow(k,(n-k)) ) mod 19900801;
ans:=(ans+1) mod 19900801;
writeln(ans);
close(input);close(output);
end.