0916 T4 赛小城学数学

题面:
题目描述 众所周知,赛小城是一个爱打瞌睡的好学生。
这一天,他又在数学课上睡觉,这令数学老师忍无可忍。说是迟,那是快,数学老师一个箭步飞奔过去,敲醒了赛小城。并给出了一道极难的数学题,让他清醒一下。题意如下:从1 − N中找一些数乘起来使得答案是一个完全平方数,求这个完全平方数最大可能是多少。赛小城退役已久,码力不够犯了难。于是赛小城找到了你,作为一名OIer,你能帮帮他么?
输入描述 一个数 N
输出描述 一行一个整数代表答案对100000007取模之后的答案。
样例输入 7
样例输出 144
数据范围及提示 对于30%的数据,1≤N≤100。
对于50%的数据,1≤N≤5000。
对于70%的数据,1≤N≤〖10〗^5。
对于100%的数据,1≤N≤5×〖10〗^6。

题解:

1到n中选择一些数,使它们相乘是完全平方数,求最大的完全平方数;

将1-n质因数分解,统计每个质数的次数;
若次数为偶,则计入答案;
若次数为奇,则-1计入答案;
快速幂求解;

**正确性证明:**
对于算法正确性,关键在于确定一个数不会部分被取,部分不被取;
偶数次幂不作处理;
对于奇数次幂的-1,可以理解为将他本身从连乘中删去;
那么删去的数都是质数,也就不存在一个数部分被取,部分不被取;

**统计质因数的方法:**
f(a)=n/a+n/(a^2)+n/(a^3)+.....+n/(a^k) a^k<=n,a^(k+1)>n
以从1-9中统计2为例(有2的只有2,4,6,8,);
     2   4   6    8
2   √   √   √   √   4
2^2      √       √   2  
2^31
显然,分层统计了2的次数; 

代码:

#include<iostream>
#include<cstdio>
using namespace std;
const int p=100000007;
long long n,num=1,cnt;
bool used[6000000];
long long tongji(int x){
    long long k=x,ans=0;
    while(k<=n){
        ans+=n/k;
        k*=x;
    }
    return ans;
}
long long mo(long long a,long long b){
    return (a%p*b%p)%p;
}
long long ksm(long long x,long long y){
    long long r=1,base=x;
    while(y){
        if(y&1) r=mo(r,base);
        base=mo(base,base);
        y=y>>1;
    }
    return r;
}
int main(){
freopen("pow.in","r",stdin);
    freopen("pow.out","w",stdout);
    scanf("%lld",&n);
    for(int i=2;i<=n;i++){
        if(used[i]==0){
            cnt=tongji(i);
            if(cnt%2)   cnt--;
            num=mo(num,ksm(i,cnt));
            for(int j=1;i*j<=n;j++){
                used[i*j]=1;
            }
        }
    }
    printf("%lld",num);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值