【CodeForces 304A 】Pythagorean Theorem II 高斯素数 高效算法

In mathematics, the Pythagorean theorem — is a relation in Euclidean geometry among the three sides of a right-angled triangle. In terms of areas, it states:

In any right-angled triangle, the area of the square whose side is the hypotenuse (the side opposite the right angle) is equal to the sum of the areas of the squares whose sides are the two legs (the two sides that meet at a right angle).

The theorem can be written as an equation relating the lengths of the sides a, b and c, often called the Pythagorean equation:

a2 + b2 = c2
where c represents the length of the hypotenuse, and a and b represent the lengths of the other two sides.

Given n, your task is to count how many right-angled triangles with side-lengths a, b and c that satisfied an inequality 1 ≤ a ≤ b ≤ c ≤ n.

Input
The only line contains one integer n (1 ≤ n ≤ 104) as we mentioned above.

Output
Print a single integer — the answer to the problem.

Examples
Input
5
Output
1
Input
74
Output
35

题意:求出n以内的勾股数组数

思路:

这题暴力当然可以,但是这里介绍一种更高效的方法——高斯素数。我用这个方法本题只跑了124ms,也就是说数据量再乘10也可以A掉。
介绍之前先给出一个洛谷的高斯素数模板题:圆上的整点
这是一个和本题类似的题,给你一个r,问圆上有多少整数点满足a2 + b 2 = r2 。利用高斯素数的性质,将一个数分解成其质因数相乘的形式之后(唯一分解定理),若其中的质因数可以分解为高斯素数,则对答案的贡献就是其指数+1。那怎么判断一个数是不是高斯素数呢?
1.满足4n+1的质因数可以分解为高斯素数
2.若该数是4n+3的形式(只有这4n+1和4n+3这两种情况,因为质数首先是奇数),则指数为奇数时不可能有解,反之不变。
所以对于这题只需要枚举一次1->n然后对每个数看能分解出的整数解即可。时间复杂度O(nlogn)。

关于算法的推导和理解视频:传送门

AC代码:

#include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include <queue>
#include<sstream>
#include <stack>
#include <set>
#include <bitset>
#include<vector>
#define FAST ios::sync_with_stdio(false)
#define abs(a) ((a)>=0?(a):-(a))
#define sz(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
#define mem(a,b) memset(a,b,sizeof(a))
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define rep(i,a,n) for(int i=a;i<=n;++i)
#define per(i,n,a) for(int i=n;i>=a;--i)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<ll,ll> PII;
const int maxn = 1e6+200;
const int inf=0x3f3f3f3f;
const double eps = 1e-7;
const double pi=acos(-1.0);
const int mod = 1e9+7;
inline int lowbit(int x){return x&(-x);}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y){if(!b){d=a,x=1,y=0;}else{ex_gcd(b,a%b,d,y,x);y-=x*(a/b);}}//x=(x%(b/d)+(b/d))%(b/d);
inline ll qpow(ll a,ll b,ll MOD=mod){ll res=1;a%=MOD;while(b>0){if(b&1)res=res*a%MOD;a=a*a%MOD;b>>=1;}return res;}
inline ll inv(ll x,ll p){return qpow(x,p-2,p);}
inline ll Jos(ll n,ll k,ll s=1){ll res=0;rep(i,1,n+1) res=(res+k)%i;return (res+s)%n;}
inline ll read(){ ll f = 1; ll x = 0;char ch = getchar();while(ch>'9'||ch<'0') {if(ch=='-') f=-1; ch = getchar();}while(ch>='0'&&ch<='9') x = (x<<3) + (x<<1) + ch - '0',  ch = getchar();return x*f; }
int dir[4][2] = { {1,0}, {-1,0},{0,1},{0,-1} };
int main()
{
    ll m;
    scanf("%lld",&m);
    ll sum = 0;
    rep(i,1,m)
    {
        ll n = i;
        n=n*n;
        int now=2;
        long long ans=1;
        while(n!=1)
        {
            if(n%now!=0)
            {
                now++;
                continue;
            }
            int cnt=0;
            while(n%now==0)     //唯一分解定理
            {
                n/=now;
                cnt++;      //求出指数
            }
            if(now%2==0)
            {
                now++;
                continue;
            }
            else if(now%4==1)   //若可分解为为高斯素数
                ans*=(cnt+1); //指数+1就是方案数

            else if(cnt%2)  //即是now%4==3且指数为奇数(个数就是偶数个)
            {
                ans=0;    //如果不能分解为高斯素数,且个数为偶数个,那么肯定没有整数解
                break;
            }
            now++;
        }
        sum += (ans-1)/2;       //减去座标轴上的,同时去重
    }

    printf("%lld\n",sum);
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章