三元组数量的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,现在就统计出来结果了

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值