解题思路:算法
题目说明:测试
时间限制: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做为差分的逆运算,对这个公式进行逆向回推,能够获得与统计分析如出一辙的结论。
这是这个问题的数学模型。
可是很操蛋的是,测试数据很是大。
因此在技术细节上
这个公式的计算有着巧妙的技巧....来避免溢出