1. 程式人生 > >楊輝三角 x

楊輝三角 x

ger style std 查看 準備 -a clas 出了 分析

楊輝三角是美麗的數學結晶,其結論往往多蘊含自然之美.

                ——以下內容均摘抄自題解.

例題:

洛谷P1762 偶數

正如這題所示,數據在n<=10^15的範圍內則引導我們去尋找空間更節省,速率更高效的算法。

首先,很明顯,楊輝三角之特點在於其行數即等於每行的數字數。因此,可以很容易使用求和公式求出1到n行一共有多少個數字。

其次,通過觀察,可以發現,奇數個數比偶數個數更有規律,其規律在於:

  1. 每行奇數個數一定為2^k(k為自然數)

  2. 當行數恰為2^k(k為自然數)時,奇數個數為2^k,偶數個數為零

  3. 當行數恰為2^k(k為自然數)時,奇數個數和恰為3^(k-1)

  4. 更巧妙的是:這個規律能更加擴展到一個不為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的分解,求出奇數總個數。

所以,偶數總個數也就不難得出了。

  1. 這樣,我們就將一個看起來很困難的大量數求和,降級為極具規律性的數學公式求法。問題也順理成章轉化為如何將一個數分解為若幹項2^k的和的形式。通過分析,我們知道算法的復雜度是O(logn)級的,足夠通過所有的數據。

  2. 這道題目構思精巧,邏輯嚴密,能夠告訴我們規律的尋找是一個漫長的探索過程,但是一旦得出了規律,世間萬物自然水落石出!這個算法的正確性能夠通過數學證明的,此處不贅述。

  3. 不要忘了膜題目要求的數字哦!

下面附探索規律的表格:

首先找規律什麽的....(除了這個,其實也不一定對~~~~)

/*
                                         前  前        前    前
                                    每   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