解题报告 Valentine‘s present

 

1.        题目

3Valentine’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):AA 。求满足 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.

 

 

posted @ 2011-08-09 15:15  木小漾  阅读(319)  评论(0编辑  收藏  举报