2019.7.9 校内测试题 平方根

 题目

 平方根(sqrt.cpp,1s,128MB)

【问题描述】:

  给出一个正整数 n(1<n<=2^31-1),求当 x,y 都为正整数,方程: sqrt(n)=sqrt(x)-sqrt(y) 的解中,x 的最小值是多少?

【输入文件】:

   输入文件 sqrt.in 只有一行,一个正整数 n。

【输出文件】:

  输出文件 sqrt.out 只有一行,即满足条件的最小的 x 的解。

【输入输出样例】

   sqrt.in   4

   sqrt.out   9

【数据规模】:

  30%的数据满足 1<n<=10000 100%的数据满足 1<n<=2^31-1。

 

 

考试得分:  30

 

 

主要算法 :  质数(质因数分解)

 

 

应试策略:

  1.   看到根式sqrt(n)=sqrt(x)-sqrt(y),又因为三者都是正整数,所以x>n,数学老师经常说遇到根式就平方,但是怎样平方呢?需要分离变量吗?
  2.   首先将等式进行变换,分离变量y=x+n-2*sqrt(x*n),又因为y为整数,所以sqrt(x*n)也为整数
  3.        n是已知量,从小到大枚举x就可以算出sqrt(x*n)是否是整数就行
  4.        符合条件就过河拆桥式输出    

   代码

#include<math.h>
#include<stdio.h>
#include<stdlib.h>
#define FORa(i,s,e) for(int i=s;i<=e;i++)
#define FORs(i,s,e) for(int i=s;i>=e;i--)
#define gc pa==pb&&(pb=(pa=buf)+fread(buf,1,10000,stdin),pa==pb)?EOF:*pa++
#define File(name) freopen(name".in","r",stdin),freopen(name".out","w",stdout)

using namespace std;
static char buf[10000],*pa=buf,*pb=buf;
inline int read();

int n,t;
long double p1;
long long p2;
int main()
{
    File("sqrt");
    n=read();
    while(++t)
    {
        p1=n+t+2*sqrt(t*n),p2=p1;
        if(p1==p2) {printf("%lld",p2);return 0;}
    }
    printf("NO WAY!");
    return 0;
}
inline int read()
{
    register int x(0);register int f(1);register char c(gc);
    while(c<'0'||c>'9') f=c=='-'?-1:1,c=gc;
    while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=gc;
    return x*f;
}

 

 

非完美算法:  

    照搬应试策略

 

 

正解:

  1.   沿袭应试策略的1,2点的基础上,在判断sqrt(x*n)上进行优化
  2.        已知x*n必须是完全平方数,那么将其乘积数进行质因数分解,那么质因数的幂模2都为0
  3.        所以将已知量n进行质因数分解,把质因数的幂模2不是0的数筛选出来,将x变为筛选出数的乘积,得到一个暂时符合条件下的替补x
  4.        又因为x>n,所以在x的基础上再乘上以个平方数,直到乘积大于n就输出

  代码

#include<math.h>
#include<stdio.h>
#include<stdlib.h>
#define LL long long 
#define FORa(i,s,e) for(LL i=s;i<=e;i++)
#define FORs(i,s,e) for(LL i=s;i>=e;i--)
#define gc pa==pb&&(pb=(pa=buf)+fread(buf,1,10000,stdin),pa==pb)?EOF:*pa++
#define File(name) freopen(name".in","r",stdin),freopen(name".out","w",stdout)

using namespace std;
static char buf[10000],*pa=buf,*pb=buf;
inline LL read();

LL n,t,cnt,x=1;
long double p1;
long long p2;
struct Node{
    LL p,k;
}a[32];
int main()
{
    File("sqrt");
    n=read();
    LL p=n;
    FORa(i,2,sqrt(p))
    {
        LL ct=0;
        if(p%i==0)
        {
            ++cnt,a[cnt].p=i;
            while(p%i==0) ct++,p/=i;
            a[cnt].k=ct;
        }
    }
    if(p>1) a[++cnt].p=p,a[cnt].k=1;
    FORa(i,1,cnt)  if(a[i].k%2==1) x*=a[i].p;
    LL t=2;
    while(x*t*t<=n) t++;
    printf("%lld",x*t*t);  
    return 0;
}
inline LL read()
{
    register LL x(0);register LL f(1);register char c(gc);
    while(c<'0'||c>'9') f=c=='-'?-1:1,c=gc;
    while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=gc;
    return x*f;
}

 

 

 

总结:

  1.   现将数学式子化为“最简式”,在根据数学基本知识思考
  2.        暴力打起来就是要快而准,但是正解至少也要思考
  3.        枚举将位置变成已知,尽可能消元

 

 

 

 

 

 

posted @ 2019-07-09 16:55  SeanOcean  阅读(313)  评论(0编辑  收藏  举报