/*{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}) */ #include <stdio.h> #include <iostream> #include <string> #include <cmath> #include <ctime> #include <vector> #include <map> using namespace std; //x, x+d, x+2d N //等差三元组中x>0 d>0 //(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; //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是正整数 #define GetN (long long(d)*(2*x+3*d)-x*x) #define MAX 50000000 static int *count_map; static int *count_map2; class Test { public: static map<vector<int,int>,int> stored_map; static void create_map(){//方法一:因式分解 int p,q; count_map = new int[MAX+1]; for(int i=0;i<=MAX;++i) count_map[i]=0; for(p=1;p<=MAX;++p){ q=4-p%4; int p3 = p/3+2; //3*q-p>=4转化,防止while内多次计算 while(q<=MAX){ int temp = p*q; if(temp>MAX) break; if(q>=p3) { ++count_map[temp]; } q+=4; } } } static void create_map2(){/*方法二:解方程 2*x*d+3*d^2-x^2=N => d^2 - (x/2-d/2)^2 = N > d^2-(d-0.5)^2 => d<=N/4+1 其中x = d + sqrt(4*d^2-N)或 d-sqrt(4*d^2-N) 由此d从1到N/4+1循环,delta = sqrt(4*d^2-N)从最小值max(0,sqrt(4*d^2-Nmax)) 到2*d循环进行最大范围的统计,不同delta和d组成不同的x和d,也就是不同的三元组 时间复杂度小于n^2,和nlog(n)比应该比较接近*/ int d; int x; count_map2 = new int[MAX+1]; for(int i=0;i<=MAX;++i) count_map2[i]=0; for(d=1;d<=MAX/4+1;++d){ long long d4_2 = (long long)4*d*d; //d4_2 = 4*d^2 int delta=0; if(d4_2>MAX) delta = sqrt((double)(d4_2-MAX)); int d2 = 2*d; while(delta<d2){ long long delta_2 =(long long)delta*delta; int n = d4_2 - delta_2; if(n<=MAX){ if(delta>0&&d-delta>0) ++count_map2[n]; ++count_map2[n]; } ++delta; } } } static int Count (int a,int b) { static bool first = true; if(first){ first=false; clock_t t1=clock(); create_map(); clock_t t2=clock(); std::cout<<(t2-t1)/(double)CLOCKS_PER_SEC<<" s"<<std::endl; cout<<"map2:"<<endl; t1=clock(); create_map2(); t2=clock(); std::cout<<(t2-t1)/(double)CLOCKS_PER_SEC<<" s"<<std::endl; } int ret = 0; for(int i=a;i<=b;++i){ ret+=count_map[i]*(count_map[i]-1); //if(count_map[i]!=count_map2[i]) cout<<i<<":"<<count_map[i]<<","<<count_map2[i]<<endl; } return ret/2; } }; //start 提示:自动阅卷起始唯一标识,请勿删除或增加。 int main() { int a,b; while(1){ cin>>a>>b; cout<<Test::Count(a,b)<<endl; } } //end //提示:自动阅卷结束唯一标识,请勿删除或增加。
//开始用解方程的方法想一个n一个n求,发现超时,改成所有范围内的数一次求完并做记录,以后只要查询就直接获得结果,这样就没有超三秒了。
pongo(csdn英雄会题解)之三元组的数量--英雄会第二届在线编程大赛·优快云现场决赛
最新推荐文章于 2024-09-02 16:35:55 发布