您的位置:首页 > 编程语言

pongo(csdn英雄会题解)之三元组的数量--英雄会第二届在线编程大赛·CSDN现场决赛

2013-12-30 00:23 309 查看
今天来CSDN参加了现场的决赛,我完全是为了看大神而来,开赛10分钟,cp大神就ac了,我那会还没思路,开始看错了题,后来想到了一种方法,到最后cp讲题解的时候,才发现我的想法基本和他的一样,那会我程序还没调试出来,今天切身体会到什么是高手。

下面是题目:

{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})

我的解法:
(1)首先为a到b的每个N值设置一个统计量,可以通过数组实现;

(2)三元组由起始值x和等差确定,即 x,x+d,x+2d,我们可以通过统计x和d来求得N,并将相应的统计量+1;

(3)最后统计对应每个N值的三元组数量,即可解题。

但是这样x和d无法枚举,继续:

由上面得(x+2d)^2-(x+d)^2-x^2=-x^2+2dx+3d^2=(3d-x)(x+d)=N;

另设p=3d-x ; q=x+d; 那么得:p*q=N ; d=(p+q)/4; x=(3q-p)/4;

(注:上面在给a = 1,b = 30例子时没有给{0,3,6}与{12,9,6}这对,说明x的起始值应大于0)

所以得出下面四个限制条件:

1) p+q能被4整除;

2) 3q-p大于等于4(q>=p/3+2);(条件1、2能推出3q-p能被4整除:因为3q-p+p+q=4p)

3) a=<p*q<=b

4)p,q是正整数

由上面4个限制条件我们可以通过枚举所有满足以上四个条件的p、q来计算出相应的N值,将相应的统计量+1;

你是否会想当不同的p、q计算相同N值的时候是否会是同一个三元组?那么我们假设存在这种情况,那么:

x1=(3*q1-p1)/4 == x2=(3*q2-p2)/4 ;

d1=(p1+q1)/4 == d2=(p2+q2)/4 ;

解得p1==p2; q1==q2

所以说明只有当p、q两个值都相同时才对应同一个三元组,所以通过枚举p、q,利用上面的4个限制条件解题,转换为C++代码为:

#include <stdio.h>
#include <iostream>
#include <string>
using namespace std;
class Test {
public:
	static long Count (int   a,int   b){
		int res=0;
		int *resA=new int[b-a+1];
		for(int i=0;i<=b-a;++i)
			resA[i]=0;
		for(int p=1;p<=b;++p){
			int d=p/4+1;//是为了下一行代码中,q的枚举初始值>=1,以减少没必要的枚举		
			int q=4*d-p;//保证p+q能被4整除
			int p3=p/3+2;//防止while循环里面重复计算p/3+2
			while(q<=b){
				int tmp=p*q;
				if(tmp>b)break;//p*q<=b
				if(q>=p3){
					if(tmp>=a)//p*q>=a
						++resA[tmp-a];
				}
				q+=4;//每次q增加4,保证p+q能被4整除
			}
		}
		//计算Cx,2
		for(int i=0;i<=b-a;++i)
			res+=resA[i]*(resA[i]-1);
		res/=2;
		return res;
    }

};
//start 提示:自动阅卷起始唯一标识,请勿删除或增加。
int main()
{   
    cout<<Test::Count(1,30)<<endl;  
	return 0;
} 
//end //提示:自动阅卷结束唯一标识,请勿删除或增加。


显然复杂度为sum (1/4*b/i),i=1....b,根据调和级数得,O(blogb)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐