题面:
题目描述 众所周知,赛小城是一个爱打瞌睡的好学生。
这一天,他又在数学课上睡觉,这令数学老师忍无可忍。说是迟,那是快,数学老师一个箭步飞奔过去,敲醒了赛小城。并给出了一道极难的数学题,让他清醒一下。题意如下:从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^3 √ 1
显然,分层统计了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;
}