完全平方数

题目描述
一个数如果是另一个整数的完全平方,那么我们就称这个数为完全平方数(Pefect Sqaure),也称平方数。

小A认为所有的平方数都是很perfect的~

于是他给了小B一个任务:用任意个不大于n的不同的正整数相乘得到完全平方数,并且小A希望这个平方数越大越好。

请你帮助小B告诉小A满足题意的最大的完全平方数。
输入
输入文件名为number.in 
输入仅 1行,一个数n。
输出
输出文件名为number.out
输出仅1行,一个数表示答案。由于答案可以很大,所以请输出答案对100000007取模后的结果。
样例1】
number.in
7
number.out
144
【样例解释1】
144=2×3×4×6,是12的完全平方。
【样例2】
number.in  
9
number.out
5184
【样例解释2】
5184=3×4×6×8×9,是72的完全平方。
提示
【数据范围】
对于20%的数据,0<n≤100;
对于50%的数据,0<n≤5,000;
对于70%的数据,0<n≤100,000;
对于100%的数据,0<n≤5,000,000。
来源

2013学军中学noip模拟day2


solution:要生成一个完全平方数,它必定是由2的偶数次方*3的偶数次方*5的偶数次方。。。。。。等等质数的偶数次方。因此我们可以很自然地想到分解质数,那么怎么求出500万之内的质数呢?普通的一个个枚举太慢,只能用筛法。其次,我们就要2--n中所有质数的次方数了,也就是一一分解它们,那么我们最后求答案要怎么求呢?如果碰到某个质数是奇数次方,该怎么办?其实很简单,直接把那个光杆质数扔掉就行了阿!

但是,一测大数据,我发现超时超得一塌糊涂,再调了一下,发现500万的质数有34万多个,如果一个一个唯一分解,到了一些大数的时候,每个都要遍历几十万个质数,还不爆?

后来,sk大神告诉了我他百度来的方法,直接用n除每个质数,然后加上每次剩下的即可,为何可以这样?我来举个例子:用9除2:

4  1——n中唯一分解中有1个2的有4个数

2 有2个2

1 有3个2

这样就能快速算出每个质数有几次方了。Orz。。。。。。。

第一次超%30的代码

#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
const int m=100000007;
int n,l;
long long ans;
int p[5000005],a[350000],b[350000];
int main()
{
    ans=1;
    cin>>n;
    int x=int(sqrt(n));
    for(int i=2;i<=x;i++)
    if(p[i]==0)
    {
        int y=n/i;
        for(int j=2;j<=y;j++) p[i*j]=1;
    }
    for(int i=2;i<=n;i++)
    if(p[i]==0)
    {
        l++;
        a[l]=i;
    }
    for(int i=2;i<=n;i++)
    {
        int x=i;
        int k=0;
        while(x!=1)
        {
            k++;
            while(x%a[k]==0)
            {
                x=x/a[k];
                b[k]++;
            }
        }
    }
    for(int i=1;i<=l;i++)
    {
        if(b[i]%2==1) b[i]--;
        for(int j=1;j<=b[i];j++) ans=(ans*a[i])%m;
    }
    cout<<ans<<endl;
    return 0;
}
AC的代码

#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
const int m=100000007;
int n,x,l;
long long ans;
int p[5000005],a[350000],b[350000];
int main()
{
    ans=1;
    cin>>n;
    x=int(sqrt(n));
    for(int i=2;i<=x;i++)
    if(p[i]==0)
    {
        int y=n/i;
        for(int j=2;j<=y;j++) p[i*j]=1;
    }
    for(int i=2;i<=n;i++)
    if(p[i]==0)
    {
        l++;
        a[l]=i;
    }
    for(int i=1;i<=l;i++)
    {
        x=n;
        while(x/a[i]>0)
        {
            x=x/a[i];
            b[i]=b[i]+x;
        }
    }
    for(int i=1;i<=l;i++)
    {
        if(b[i]%2==1) b[i]--;
        for(int j=1;j<=b[i];j++) ans=(ans*a[i])%m;
    }
    cout<<ans<<endl;
    return 0;
}



  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值