/*{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求,发现超时,改成所有范围内的数一次求完并做记录,以后只要查询就直接获得结果,这样就没有超三秒了。