2014编程之美资格赛 第二题 大神和三个小伙伴

解题思路:算法

  1. 暴搜得到Raw Data
  2. 找出规律,通项表达式

题目说明:测试

时间限制:2000ms大数据

单点时限:1000msspa

内存限制:256MBcode

描述blog

L国是一个有着优美景色且物产丰富的国家,不少人都喜欢来这里旅游而且喜欢带走一些记念品,大神同窗也不例外。距离开L国的时间愈来愈近了,大神同窗正在烦恼给她可爱的小伙伴们带什么记念品好,如今摆在大神同窗面前的有三类记念品A, B, C能够选择,每类记念品各有N种。其中种类为A_i, B_i, C_i的记念品价值均为i, 且分别有N+1-i个剩余。如今大神同窗但愿在三类记念品中各挑选一件而后赠送给她的三名可爱的小伙伴,可是她又不但愿刚好挑出来两件价值相同的记念品,由于这样拿到相同价值记念品的两位小伙伴就会认为大神同窗偏袒另外一位小伙伴而不理睬她超过一星期。如今,大神同窗但愿你买到的三件记念品能让三位小伙伴都开心而且不和她闹别扭,她想知道一共有多少种不一样挑选的方法?内存

由于方案数可能很是大,大神同窗但愿知道挑选记念品的方案数模10^9+7以后的答案。ci

 

输入数学

第一行包括一个数T,表示数据的组数。it

接下来包含T组数据,每组数据一行,包括一个整数N。

输出

对于每组数据,输出一行“Case x: ”,其中x表示每组数据的编号(从1开始),后接一个数,表示模10^9+7后的选择记念品的方案数。

 

数据范围

小数据:

1<=T<=10

1<=N<=100

大数据:

1<=T<=1000

1<=N<=10^18

 

样例解释

对于第二组数据,合法的方案有如下几种,(X,Y,Z)表示选择了A类记念品中价值为X的,B类记念品中价值为Y的,C类记念品中价值为Z的。

(1,1,1): 3*3*3=27种

(1,2,3): 3*2*1=6种

(1,3,2): 3*1*2=6种

(2,1,3): 2*3*1=6种

(2,2,2): 2*2*2=8种

(2,3,1): 2*1*3=6种

(3,1,2): 1*3*2=6种

(3,2,1): 1*2*3=6种

(3,3,3): 1*1*1=1种

一共27+6+6+6+8+6+6+6+1=72种选择记念品的方案

注意,如(1,1,2), (2,3,3), (3,1,3)都由于刚好选择了两件价值相同的记念品,因此并非一种符合要求的记念品选择方法。

 

 

 

样例输入

2

1

3

样例输出

Case 1: 1

Case 2: 72


解决思路

 1.暴力解决

暴搜的代码:

这个很简单,直接遍历全部可能的价值组合,并计算每种价值组合的子选择组合。

直接用暴力破解的时间复杂度为O(n^3) 。很明显,对于题目要求的输入规模范围,直接用暴力是不可行的。

 1 for (int turn_count = 0; turn_count < T; turn_count++)
 2     {
 3         sum = 0;
 4         N = turns[turn_count];
 5         
 6         for (int i = 1; i <= N; i++)
 7         {
 8             for (int j = 1; j <= N; j++)
 9             {
10                 for (int k = 1; k <= N; k++)
11                 {
12                     if ((i == j || j == k || k == i) && !(i == j && j == k))
13                     {//if exists two equal value ,then break.
14                         continue;
15                     }
16                     sum += count(i, j, k);
17                     result = sum % (1000000007);
18                 }
19             }
20 
21         }
22 
23         printf("Case %d: %d\n", turn_count+1, (int)sum);
24     }


而后得到一些Raw Data,为下一步求得通项作准备。

这是一组原始数据:

1

1

2

9

3

72

4

400

5

1575

6

4851

7

12544

8

28512

9

58725

10

111925

11

200376

12

340704

13

554827

14

870975

15

1324800

16

1960576

17

2832489

18

4006017

19

5559400

20

7585200

 

2.求得通项

最简单的方法:采用统计学方法。

由数学直觉,能够推断这是一个多项式的通项。

直接用Matlab执行 polyfit(x,y,10);

拿一个十次多项式拟合。果真,获得了很漂亮的数据:

一秒解决问题。

   2        2   2
  n  (n + 1)  (n  - 3 n + 4)
  --------------------------
              8                                                 

可是,这么搞很明显没有理论支持。所以有必要对整个过程进行一次分析:

结论就摆在这里了,对原理没有兴趣的同窗能够直接略过了。

 

1

1

1

0

0

0

0

0

 

2

9

9

0

0

0

0

0

 

3

72

36

36

6

6

2

2

12

4

400

100

300

50

44

11

9

13 23

5

1575

225

1350

225

175

35

24

14 24 34

6

4851

441

4410

735

510

85

50

15 25 35 45

7

12544

784

11760

1960

1225

175

90

16 26….56

8

28512

1296

27216

4536

2576

322

147

 

9

58725

2025

56700

9450

4914

546

224

 

10

111925

3025

108900

18150

8700

870

324

 

11

200376

4356

196020

32670

14520

1320

450

 

12

340704

6084

334620

55770

23100

1925

605

 

13

554827

8281

546546

91091

35321

2717

792

 

14

870975

11025

859950

143325

52234

3731

1014

 

15

1324800

14400

1310400

218400

75075

5005

1274

 

16

1960576

18496

1942080

323680

105280

6580

1575

 

17

2832489

23409

2809080

468180

144500

8500

1920

 

18

4006017

29241

3976776

662796

194616

10812

2312

 

19

5559400

36100

5523300

920550

257754

13566

2754

 

20

7585200

44100

7541100

1256850

336300

16815

3249

 

N

实际结果

(x,x,x)

三个不一样的组合数

除6修正

增量

增量分析:因子

项数

正向分析:

这个问题能够仍然抽象为几率论中通用的球和盒子的问题形式。

能够理解为三个球,放入N个盒子中。 且编号为i的盒子里面有N+1-i个格子。一个格子能够放多个球。

约束条件为:一个盒子内不能够刚好有两个球;问这三个球的不一样放法。

 

为了解决这个问题,能够绘制一张表格:

第一列:N的序号

第二列:暴力计算获得的原始数据

 

第一步,放法能够划分为两个子类:三个球放入同一个盒子中,三个球放入三个不一样的盒子中。对于第一种状况:可能的状况种类是容易计算的,即,放入同一个盒子i的可能组合有i^3种。那么总共的可能性就是i^3 从1到N的级数和(n(n+1)/2)^2 。获得的结果放在第三列

 

第二步,考虑三个球放入三个不一样盒子中的状况。

用暴力算法获得的数据,减去放入同一个盒子的组合数,获得放入不一样盒子的组合数。结果放入第四列

 

第三步,咱们能够发现,ABC三者的次序对于本问题研究并没有影响,所以对排列数进行废序处理。

除以3! 。获得无序的子整体个数,放入第五列。

 

第四步,当从N=k-1过分到N=k时,咱们对后者中的组合状况进行一次划分:{选择了价值为k物品的组合,和没有选择价值k物品的组合}。前者刚好是从N=k-1到N=k的增量,咱们须要关注增量,所以对第五列的数据差分后,在数据第一项前补0。结果放入第六列

 

第五步,咱们发现第i项组合数,老是表示为i与一个数的乘积,是由于每种价值组合的子组合数计算公式:(N+1-i1)* (N+1-i2)* (N+1-i3)中,都含有因子i。所以,去除这个因子的影响。将结果放入第7列

 

第六步,咱们终于能够发现直观的规律了。第八列的数据,咱们能够转换为第九列的形式:

(1+…+N-2)*(N-1)

而后用Matlab级数求和命令symsum做为差分的逆运算,对这个公式进行逆向回推,能够获得与统计分析如出一辙的结论。

 

这是这个问题的数学模型。

可是很操蛋的是,测试数据很是大。

因此在技术细节上

这个公式的计算有着巧妙的技巧....来避免溢出

相关文章
相关标签/搜索