很是遺憾,忘記看郵箱了,所以沒去參加這個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,現在就統計出來結果了