【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;
}

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