Sticks and Right Triangle
Time Limit: 12000/4000 MS (Java/Others) Memory Limit: 65535/65536 K (Java/Others)Total Submission(s): 793 Accepted Submission(s): 314
Problem Description
We have a stick with infinite length. Now we want to cut 3 sub-sticks with length x, y, z which is not large than L to form a right triangle. With unknown reasons we assume that x, y, z are all integers and satisfy that x, y, z are all co-primed each other. We want to know how many right triangles are there exist under our constraints
Input
The first line of input is an integer T (T<=5) indicating the number of test cases.
Each case contains a single integer L (L<=1,000,000,000,000).
Each case contains a single integer L (L<=1,000,000,000,000).
Output
For each test case output a single integer in one line, indicating the number of right triangles.
Sample Input
15
Sample Output
1
Hint
In our test case, we could find a right triangle (3,4,5) which satisfy 3,4,5<=5 and gcd(3,4)=1,gcd(3,5)=1,gcd(4,5)=1.
题意:给定数l,问能找到多少对a,b,c均小于等于l,使得a^2+b^2=c^2
思路:毕达哥拉斯三元组
a=2mn
b=m^2-n^2
c=m^2+n^2
m>n,二者互素且一奇一偶
①由定理可知,m,n一定<=sqrt(l),所以可以对于每个给定的l,遍历所有的可能m值,求对这个m值有多少n符合题意
②分m为奇数和偶数两种情况
1.当m为偶数时
若m<=n,则n可以取小于m的所有素数,即为m的欧拉函数值,因为与偶数互素的数一定是奇数
若m>n,则只能取小于n并且与m互素的奇数(并不是所有的奇数都与m互素),此时需要把m用算术基本定理分解成多个素数相乘的形式,然后运用容斥求得
2.当m为奇数时
若m<n,则n可以取小于m的所有与m互素的偶数,这样直接用容斥是求不出来的,因为与m互素的数里面包含着奇数和偶数,但有一定理:与奇数互素的偶数的个数等于与其1/2互素数的个数
这样直接运用定理和容斥求与m/2的互素的数的个数即为答案
若m>n,则只能取小于n并且与m互素的偶数,同样运用上面的定理加容斥求得
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <cmath>
#include <vector>
#define max_ 1000010
#define inf 0x3f3f3f3f
#define ll long long
#define les 1e-8
#define mod 9901
using namespace std;
bool vis[max_];
int p[max_];
int prime[max_];
int num,pl;
ll ans,l;
int u[35];
void getprime()
{
pl=0;
for(int i=2;i<max_;i++)
{
if(vis[i]==false)
prime[pl++]=i;
for(int j=0;j<pl&&prime[j]*i<max_;j++)
{
vis[i*prime[j]]=true;
if(i%prime[j]==0)
break;
}
}
}
void getphi()
{
for(int i=1;i<max_;i++)
{
p[i]=i;
if(i%2==0)
p[i]>>=1;
}
for(int i=3;i<max_;i+=2)
{
if(p[i]==i)
{
for(int j=i;j<max_;j+=i)
p[j]-=p[j]/i;
}
}
}
void breakprime(int x)
{
num=0;
if(vis[x]==false)
{
u[num++]=x;
return;
}
for(int i=0;i<pl&&x>1;i++)
{
if(x%prime[i]==0)
{
u[num++]=prime[i];
while(x%prime[i]==0)
{
x/=prime[i];
}
if(x>1&&vis[x]==false)
{
u[num++]=x;
return;
}
}
}
}
void dfs(int x,int r,int s,int n)
{
if(x==num)
{
if(r&1)
ans-=n/s;
else
ans+=n/s;
return;
}
dfs(x+1,r,s,n);
dfs(x+1,r+1,s*u[x],n);
}
int main(int argc, char const *argv[]) {
int t;
scanf("%d",&t);
getprime();
getphi();
while(t--)
{
scanf("%lld",&l);
ans=0;
int m=(int)sqrt(1.0*l);
for(int i=m;i>=1;i--)
{
int n=(int)sqrt(l-(ll)i*i);
if(i&1)
{
breakprime(i);
if(i<=n)
dfs(0,0,1,i>>1);
else
dfs(0,0,1,n>>1);
}
else
{
if(i<=n)
ans+=p[i];
else
{
breakprime(i);
dfs(0,0,1,n);
}
}
}
printf("%lld\n",ans);
}
return 0;
}