楊輝三角 x
楊輝三角是美麗的數學結晶,其結論往往多蘊含自然之美.
——以下內容均摘抄自題解.
例題:
洛谷P1762 偶數
正如這題所示,數據在n<=10^15的範圍內則引導我們去尋找空間更節省,速率更高效的算法。
首先,很明顯,楊輝三角之特點在於其行數即等於每行的數字數。因此,可以很容易使用求和公式求出1到n行一共有多少個數字。
其次,通過觀察,可以發現,奇數個數比偶數個數更有規律,其規律在於:
-
每行奇數個數一定為2^k(k為自然數)
-
當行數恰為2^k(k為自然數)時,奇數個數為2^k,偶數個數為零
-
當行數恰為2^k(k為自然數)時,奇數個數和恰為3^(k-1)
- 更巧妙的是:這個規律能更加擴展到一個不為2^k的數上,因為每一個數,都能分解為若幹項2^k的和的形式。
舉個例子吧:當n=2333;
2333= 2048+256+16+8+4+1
通過暴力程序,我們可以找出2333的所有奇數個數為190985
那麽,我們找出如下數字
行數 所有奇數個數
2048 177147
256 6561
16 81
8 27 4 9 1 1
我們可以巧妙發現:177147 + 6561*2 + 81*4 + 27*8 + 9*16 + 1*32恰好等於190985!
那麽,通過以上的探索,我們就能通過對n的分解,求出奇數總個數。
所以,偶數總個數也就不難得出了。
-
這樣,我們就將一個看起來很困難的大量數求和,降級為極具規律性的數學公式求法。問題也順理成章轉化為如何將一個數分解為若幹項2^k的和的形式。通過分析,我們知道算法的復雜度是O(logn)級的,足夠通過所有的數據。
-
這道題目構思精巧,邏輯嚴密,能夠告訴我們規律的尋找是一個漫長的探索過程,但是一旦得出了規律,世間萬物自然水落石出!這個算法的正確性能夠通過數學證明的,此處不贅述。
- 不要忘了膜題目要求的數字哦!
下面附探索規律的表格:
首先找規律什麽的....(除了這個,其實也不一定對~~~~)
/* 前 前 前 前 每 i i 每 i i 排 排 排 排 排 排 偶 偶 偶 奇 奇 奇 數 數 數 數 數 數 個 個 和 個 個 和*/ 1 0 0 0 1 1 1 1 1 0 0 0 2 3 3 1 2 1 1 1 2 2 5 5 1 3 3 1 0 1 2 4 9 7 1 4 6 4 1 3 4 16 2 11 9 1 5 10 10 5 1 2 6 26 4 15 21 1 6 15 20 15 6 1 3 9 58 4 19 53 1 7 21 35 35 21 7 1 0 9 58 8 27 128 1 8 28 56 70 56 28 8 1 7 16 254 2 29 130 1 9 36 84 126 126 84 36 9 1 6 22 746 4 33 150 ......
大佬給出的:
// 行數 該行奇數 奇數和 偶數 偶數和 總數 1 1 1 0 0 1 2 ( 2) 3 0 0 3 3 ( 2) 5 1 1 6 4 ( 4) 9 0 1 10 5 ( 2) 11 3 4 15 6 ( 4) 15 2 6 21 7 ( 4) 19 3 9 28 8 ( 8) 27 0 9 36 9 ( 2) 29 7 16 45 10 ( 4) 33 6 22 55 16 ( 16) 81 0 55 136 32 ( 32) 243 0 285 528 64 ( 64) 729 0 1351 2080 128 (128) 2187 0 6069 8256 256 (256) 6561 0 26335 32896 512 (512) 19683 0 111645 131328 1024 (1024) 59049 0 465751 524800 2048 (2048) 177147 0 1921029 2098176 4096 (4096) 531441 0 7859215 8390656
下面附探索規律的輔助程序:
#include <cstdio> using namespace std; int t, i, j, ou, line, e, tot; int mp[10005][10005]; int judge(int x) { int v=1; while (v<x) { v *=2; } if (v==x) return 1; else return 0; } int main() {// Input an integer in 10000! scanf("%d",&e); mp[1][1]=1; ou = line = 0; tot = 1; //行數(該行總數) 該行奇數 所有奇數 該行偶數 所有偶數 總數 printf(" 1 1 1 0 0 1\n"); for (i=2; i<=e; ++i) { line=0; for (j=1; j<=i; ++j) { mp[i][j]=mp[i-1][j-1]+mp[i-1][j]; if (mp[i][j]%2==0) ++line; } ou += line; tot += i; if (judge(i)==1)//保留該行可只查看N=2^k(k為自然數)的結果,若省略則查看所有結果 printf("%5d %5d %5d %5d %5d %5d\n", i, i-line, tot-ou, line, ou, tot); } return 0; }
附參考主程序:
#include <cstdio> #define mo 1000003 using namespace std; long long n, d, z, ans, a[55], b[55], v, p; int i, t; int main() { scanf("%lld",&v); n = v; z = 1; d = z << 50; //因為2^50恰好大於10^15 t = 50; while (n != 0) { if (n >= d) { n = n-d; a[++a[0]] = t; //將2^t 的t存入數組中 } d /= 2; t--; } b[0] = 1; for (i=1; i<=a[1]; ++i) b[i]=(b[i-1]*3)%mo; //進行預處理,準備好3^t 的數字在數組b中 for (i=1; i<=a[0]; ++i) ans += b[a[i]]*(long long)(z << i-1); //求所有奇數個數的和 p = (((z+v%mo)*(v%mo))/2); //求和公式 p %= mo; ans %= mo; if (p<ans) p += mo; p = (p-ans)%mo; //總個數減去所有奇數個數就是偶數個數了 printf("%lld\n",p); return 0; }
楊輝三角 x