很是遗憾,忘记看邮箱了,所以没去参加这个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,现在就统计出来结果了