1221. 四平方和

1221. 四平方和

这个题有很多的方法,
三重循环爆搜(不行)
二分
Hash表(不行)


  1. C++里的Hash表是unordered_map。里面的查找是S.count(x)S是哈希表,x是要查找的元素

这个题目最朴素的方法是四个for循环,铁定是TLE的。但是可以优化成3重循环:

三重循环(O(N3)

a2 + b2 + c2 + d2 = n
d = sqrt( n - a2 - b2 - c2)
所以只需要三重循环,然后设置一个数d,判断能不能满足即可

//三重循环暴力
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>

using namespace std;
const int N = 5e6+10;
int n;
int main()
{
    cin>>n;
    for(int a=0;a*a<=n;a++)
        for(int b=a;a*a+b*b <=n;b++)
            for(int c=b;a*a+b*b+c*c<=n;c++)
            {
                int t = n-a*a-b*b-c*c;
                int d = sqrt(t);	//出来可能不是整数,所以下面的if就不满足
                if(a*a+b*b+c*c+d*d == n)
                {
                    printf("%d %d %d %d",a,b,c,d);
                    return 0; 
                }
            }
}

二分 O(N2logn)

现在的空间越来越不值钱,而时间却越来越值钱。所以以后的做题也应该考虑 用空间换时间
因为有4个数,a b c d。所以我们考虑先将a2 + b2用一部分空间存起来,这样的时间复杂度是O(N2)。这里N不是5e6,因为每次最多找到根号n就不找了,所以N = 根号5e6 = 2236 大约为2000,O(N2) = 4*106
这里存的是一个结构体,包括平方和以及c d。

存起来之后再去循环c 和d ,如果在前面的存的数里找到了 == n - a * a - b * b就可以输出了。

这里的a b c d都是从0开始的,所以找到的第一个一定都是字典序最小的。

//二分 用空间换时间
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int N = 5e6+10;
struct node{
    int sum,a,b;
    bool operator<(const node &x)const
    {
        if(sum !=x.sum) return sum<x.sum;
        if(a!=x.a) return a<x.a;
        return b<x.b;
    }
}e[N];
int main()
{
    int n;
    int k=0;
    cin>>n;
    for(int c=0;c*c<=n;c++)
        for(int d=c;c*c+d*d<=n;d++)
        {
            e[++k] = {c*c+d*d,c,d};
        }
    sort(e+1,e+1+k);

    for(int a=0;a*a<=n;a++)
        for(int b=a;a*a+b*b <= n;b++)
        {
            int t = n-a*a-b*b;
            int l=1,r=k;
            while(l<r)
            {
                int mid = l+r>>1;
                if(e[mid].sum >= t) r=mid;
                else l=mid + 1 ;
            }
            if(e[l].sum==t)
            {
                printf("%d %d %d %d",a,b,e[l].a,e[l].b);
                return 0;
            }
        }
}

Hash表(O(N2))

理论上二分比Hash表慢,但是实际跑的时候二分比Hash快的。因为二分的常数很小,Hash的常熟很大,所谓常熟就可以理解为代码量。
Hash表的key是平方和,值是一个pair,存的是c d.
然后后面直接找一下S.count()有没有,有的话就直接输出。
这里可以直接输出的原因是因为a b c d都是从0开始找的,所以找到的第一个就是字典序最小的
Hash表的查找替换也是。第一次找到的平方和的位置一定是最小的,后面再找到了虽然结果都是平方和,但是字典序大了。

//Hash表方法
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<unordered_map>
#define x first
#define y second
using namespace std;
const int N = 5e6+10;
typedef pair<int,int> PII;
unordered_map<int,PII> S; //int是平方和,PII存的是a b

int main()
{
    int n;
    cin>>n;

    for(int c=0;c*c<=n;c++)
        for(int d=c;c*c+d*d<=n;d++)
        {
            int t = c*c+d*d;
            if(S.count(t) == 0) S[t] = {c,d};
        }

    for(int a=0;a*a<=n;a++)
        for(int b=a;a*a+b*b<=n;b++)
        {
            int t = n - a*a-b*b;
            if(S.count(t))
            {
                printf("%d %d %d %d ",a,b,S[t].x,S[t].y);
                return 0;
            }
        }
}

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值