三元組數量的c#求解-英雄會第二屆在線編程大賽·CSDN現場決賽

        很是遺憾,忘記看郵箱了,所以沒去參加這個csdn的這個現場決賽。不過,說句實話,從湖北趕到北京,估計時間也夠嗆,看完這個題,也覺得自己2小時搞定,似乎有難度,呵呵。

還是先看題目吧:

題目詳情

{5 3 1}和{7 5 3}是2組不同的等差三元組,除了等差的性質之外,還有個奇妙的地方在於:5^2 – 3^2 – 1^2 = 7^2 – 5^2 – 3^2 = N = 15。

{19 15 11}同{7 5 3}這對三元組也存在同樣的性質:19^2 – 15^2 – 11^2 = 7^2 – 5^2 – 3^2 = N = 15。

這種成對的三元組還有很多。當N = 15時,有3對,分別是{5 3 1}和{7 5 3},{5 3 1}和{19 15 11},{7 5 3}和{19 15 11}。

現給出一個區間 [a,b]求a <= N <= b 範圍內,共有多少對這樣的三元組。(1 <= a <= b <= 5*10^6)

例如:a = 1,b = 30,輸出:4。(注:共有4對,{5 3 1}和{7 5 3},{5 3 1}和{19 15 11},{7 5 3}和{19 15 11},{34 27 20}和{12 9 6})

 

根據題目要求,假設第一個等差數組的起始數爲c1,公差爲d1,第二個等差數組起始數爲c2,公差爲d2,很容易得到(c1+2*d1)^2-(c1+d1)^2-c1^2=(c2+2*d2)^2-(c2+d2)^2-c2^2=N,最終結果得到:(c1+d1)*(3*d1-c1)=(c2+d2)*(3*d2-c2)=N

我們這這兩部分分別設爲a,b,即:a*b=N

還很容易得到a+b=4*d,d爲等差數列的公差。

爲了方便計算,我們假設b=4*k+m

其中m=4-a%4;

考慮a的取值範圍,根據題目要求,a從1開始,爲了保證不重複計算,我們假設b>=a,可以得到如下的結果:

a=1                  a=2                a=3    ............................

1*(3+4*0)=3    2*(2+4*0)=4

1*(3+4*1)=7    2*(2+4*1)=12

.................      .....................   ...........................................

3,4,7,12 .......等等這些數符合N的要求,

即3=1*3   a=1,b=3,或者a=3,b=1,得出c1=0,c2=2,d=1

但是,根據題目,可以得出:c1!=c2,並且c1>0,c2>0

由此可見,c=2時,只有一組等差數列,但是,有可能在a等於其他值中出現。

所以基本思路就是:

列舉a從1開始,到上限,符合區間【A,B】中的所有N值,並計算N被分解成a*b之後,得到的c1,c2是否大於0

如果c1>0,此數N的次數+1,c2>0,再+1,由於b>=a,確保了不重複的計算。

同樣,b>=a,可以計算a的取值區間

 int maxa= (int)Math.Ceiling(Math.Sqrt(B));

for(int a=1;a<=maxa;a++)

{

    m=4-a%4;

    N=a*(m+4*k);

    k的取值範圍由區間【A,B】決定,並且由b.>=a約束

    double t = ((double)A / a - m) / 4;
                mink = (int)Math.Ceiling(t);
                if (a* a >A)
                {
                    t = (double)(a - m) / 4;
                    mink = (int)Math.Ceiling(t);
                }
                t = ((double)B / a - m) / 4;
                maxk = (int)Math.Floor(t);

        確定了k的範圍,進入循環

        for (int k = mink; k <= maxk; k++)
                {
                    if (k > 0)
                    {
                        d = (a + m + (k << 2)) >> 2;
                        N = a * (m + (k << 2));
                    }
                    else
                    {
                        N = a * m;
                        d = (a + m) >> 2;
                    }

                  //知道了N,a,b,就可以計算出c1,c2,d,並根據前面的條件判斷,當c1=c2,且>0時,因爲多計算了1次,所以減去

//比如N=15,可以根據條件得到1*15,和3*5,其中當a=1的時候c1=0,所以不計算在內,a=15,a=3,a=5,分別得到3組等差數列,所以計數值爲3

                    c1 = a - d;
                    c2 = 3 * d - a;
                    #region int[]版
                    if (c1 > 0)
                    {
                        dicint[N - A]++;
                    }
                    if (c2 > 0)
                    {
                        dicint[N - A]++;
                    }
                    if (c1 == c2 && c1 > 0)
                    {
                        dicint[N - A]--;
                    }

                    #endregion
                }

}

完成循環後,統計dicint中計數大於1的N,這個就是組合了,從n箇中取出2個,比如N=15,計數爲3,從3箇中取出2個,可以得到的組合數爲:3*2/2=3;

long count = 0;
            for (int i = A; i <= B; i++)
            {
                if (dicint[i -A] > 1)
                {
                    count += dicint[i -A] * (dicint[i - A] - 1) / 2;
                }
            }

 

ok,現在就統計出來結果了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章