51nod 1165 整边直角三角形的数量(两种解法)

 直角三角形,三条边的长度都是整数。给出周长N,求符合条件的三角形数量。
 例如:N = 120,共有3种不同的满足条件的直角3角行。分别是:{20,48,52}, {24,45,51}, {30,40,50}。
 输入:
第1行:一个数T,表示后面用作输入测试的数的数量。(1 <= T <= 50000)
第2 - T + 1行:每行1个数N(12 <= N <= 10^7)。
输出:
输出共T行,每行1个对应的数量。

解法1:所有本原直角三角形(即边为a、b、c,gcd(a,b,c)==1)可表示为两奇数s和t,s>t,gcd(s,t)==1, 边为st,(s*s-t*t)/2,(s*s+t*t)/2
反之,任意符合条件的s,t也可通过这样组成本原直角三角形
所以周长C= s*(s+t) ,对于C<=1e7,发现是s是sqrt级别的,可以s^2暴力求gcd即O(n*gcd复杂度),求出所有在数据范围内的本原直角三角形的周长
那么对于一个周长n,不同的直角三角形必定对应着不同的本原直角三角形,所以本原直角三角形周长必定是n的因子,枚举n的因子,然后统计答案

#include<bits/stdc++.h>
#define mst(a,b) memset(a,b,sizeof(a))
#define lowbit(x) (x&(-x))
#define lson        (rt<<1)
#define rson        (rt<<1|1)
using namespace std;
typedef long long ll;
typedef long long LL;
typedef unsigned long long ull;
typedef pair<ll,ll> pll;
typedef pair<ll,int>pli;
typedef pair<int,int> pii;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int maxn = 1e7+50;
const int mod = 1e9+7;
int mi[maxn],use[maxn],ggg[maxn];
void init(int c=maxn-10){
    int cc=0;
    for(int i=2; i<=c; ++i) {
        if(!mi[i])use[++cc]=i,mi[i]=i;
        int to=c/i;
        for(int j=1; j<=cc and use[j]<=to; ++j) {
            mi[use[j]*i]=use[j];
            if(i%use[j]==0) break;
        }
    }
    int u=sqrt(c);
    for(int i=3;i<=u;i+=2){
        int to=min(i-1,(c-i*i)/i);
        for(int j=1;j<=to;j+=2){
            if(__gcd(i,j)==1){
                ++ggg[i*(i+j)];
            }
        }
    }
}
int f[520],cnt[520],cc;
int d[50000],gg;
void dfs(int cur,int now){
    if(cur>cc){
        d[++gg]=now;
    }else{
        for(int i=0;i<=cnt[cur];++i){
            dfs(cur+1,now);
            now*=f[cur];
        }
    }
}
int solve(int val,int ti){
    int res=0;
    int tmp=val;
    cc=0;
    while(tmp>1){
        int v=mi[tmp];
        f[++cc]=v;
        cnt[cc]=0;
        while(tmp%v==0){
            ++cnt[cc];
            tmp/=v;
        }
    }
    gg=0;
    dfs(1,1);
    for(int i=1;i<=gg;++i)
        res+=ggg[d[i]];
    return res;
}
int main() {
#ifdef local
    freopen("in.txt","r",stdin);
//    freopen("out.txt","w",stdout);
#endif
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    init();
    int T;cin>>T;
    for(int i=1;i<=T;++i){
        int val;cin>>val;
        if(val&1)cout<<0<<"\n";
        else cout<<solve(val,i)<<"\n";

    }
    return 0;
}

 

解法2:化式子
  a*a+b*b = c*c
  a+b+c = n
-> a+b+sqrt(a*a+b*b) = n
-> sqrt(a*a+b*b) = n-a-b
-> 两边平方并化简
-> n^2 - 2an = 2bn-2ab
-> b = (n^2-2an)/(2n-2a)
令f = n-a
则 b = n(2n-2a -n)/(2f) = n(2f - n)/(2f) = n- n^2/(2f)
则有2f | n^2
再看适用范围,有
0 < a < n/3
a < b (不会有等于,abc都是整数,a=b,c=sqrt(2)a × )
得到 n > f > 2n/3 -> 2n > 2f > 4n/3
n-f < n-n^2/(2f) -> 2f^2 > n^2 -> 2f > sqrt(2)n > 4n/3
所以 sqrt(2)n < 2t < 2n
当2t确定,a也确定了
所以在n^2的因子中找符合条件的数

#include<bits/stdc++.h>
#define mst(a,b) memset(a,b,sizeof(a))
#define lowbit(x) (x&(-x))
#define lson        (rt<<1)
#define rson        (rt<<1|1)
using namespace std;
typedef long long ll;
typedef long long LL;
typedef unsigned long long ull;
typedef pair<ll,ll> pll;
typedef pair<ll,int>pli;
typedef pair<int,int> pii;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int maxn = 1e7+50;
const int mod = 1e9+7;
int mi[maxn],use[maxn],ggg[maxn];
inline int gcd(int a,int b){
    return b?gcd(b,a%b):a;
}
void init(int c=maxn-10){
    int cc=0;
    for(int i=2; i<=c; ++i) {
        if(!mi[i])use[++cc]=i,mi[i]=i;
        int to=c/i;
        for(int j=1; j<=cc and use[j]<=to; ++j) {
            mi[use[j]*i]=use[j];
            if(i%use[j]==0) break;
        }
    }
//    int u=sqrt(c);
//    for(int i=3;i<=u;i+=2){
//        int to=min(i-1,(c-i*i)/i);
//        for(int j=1;j<=to;j+=2){
//            if(gcd(i,j)==1){
//                ++ggg[i*(i+j)];
//            }
//        }
//    }
}
int f[520],cnt[520],cc;
ll d[50000],gg;
void dfs(int cur,ll now){
    if(cur>cc){
        d[++gg]=now;
    }else{
        for(int i=0;i<=cnt[cur];++i){
            dfs(cur+1,now);
            now*=f[cur];
        }
    }
}
int solve(int val,int ti){
    int res=0;
    int tmp=val;
    cc=0;
    while(tmp>1){
        int v=mi[tmp];
        f[++cc]=v;
        cnt[cc]=0;
        while(tmp%v==0){
            ++cnt[cc];
            tmp/=v;
        }
        cnt[cc]<<=1;
    }
    gg=0;
    dfs(1,1);
    int l=sqrt(2)*val,r=val<<1;
    for(int i=1;i<=gg;++i){
        ll v=d[i];
        if(v&1)continue;
        if(v>l and v<r)++res;
    }
    return res;
}
int main() {
#ifdef local
    freopen("in.txt","r",stdin);
//    freopen("out.txt","w",stdout);
#endif
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    init();
    int T;cin>>T;
    for(int i=1;i<=T;++i){
        int val;cin>>val;
        if(val&1)cout<<0<<"\n";
        else cout<<solve(val,i)<<"\n";

    }
    return 0;
}

 

发现两种解法的运行速度差不多。。。






转载于:https://www.cnblogs.com/bibibi/p/10699529.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值