解題思路:算法
題目說明:測試
時間限制: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做爲差分的逆運算,對這個公式進行逆向回推,能夠獲得與統計分析如出一轍的結論。
這是這個問題的數學模型。
可是很操蛋的是,測試數據很是大。
因此在技術細節上
這個公式的計算有着巧妙的技巧....來避免溢出