4196】Remoteland 【逆元+算數基本定理】
In the Republic of Remoteland, the people celebrate their independence day every year. However, as it was a long long time ago, nobody can remember when it was exactly. The only thing people can remember is that today, the number of days elapsed since their independence (D) is a perfect square, and moreover it is the largest possible such number one can form as a product of distinct numbers less than or equal to n.
As the years in Remoteland have 1,000,000,007 days, their citizens just need D modulo 1,000,000,007. Note that they are interested in the largest D, not in the largest D modulo 1,000,000,007.
Input
Every test case is described by a single line with an integer n, (1<=n<=10,000, 000). The input ends with a line containing 0.
Output
For each test case, output the number of days ago the Republic became independent, modulo 1,000,000,007, one per line.
Sample Input
4
9348095
6297540
0
Sample Output
4
177582252
644064736
題意:從[1,n]之間選擇若干個數字,使其為平方數,現在求最大的這個平方數。
分析: 從算數基本定理來考慮, 如果一個數字是平方數那麼其所有質因子的指數都是偶數,從這一點來考慮,[1,n]之間最大的我們首選n! , 然後我們只需要列舉n!的所有的質因子,看其質因子的指數,如果是偶數,我們不用管,但是如果是奇數,我們就要除去一個當前質因子(因為如果有當前的這個質因子的話,那麼[1,n]之間一定有一個數字正好等於當前的這個質因子,所以我們除掉一個,就相當於將這個單獨的數去掉,不會影響什麼)。
程式碼
#include<algorithm>
#include<stdio.h>
#define LL long long
using namespace std;
const int MAXN = 1e7+11;
const int MAXM = 1e7+11;
const int mod = 1e9+7;
const int inf = 0x3f3f3f3f;
int prm[MAXN+2],sz; bool su[MAXN+2]; int fac[MAXM];
void init(){
su[0]=su[1]=true;
for(int i=2;i<=MAXN;i++){
if(!su[i]) prm[++sz]=i;
for(int j=1;j<=sz;j++){
int t=i*prm[j];
if(t>MAXN) break;
su[t]=true;
if(i%prm[j]==0) break;
}
}
fac[0]=fac[1]=1;
for(int i=2;i<=MAXM;i++){
fac[i]=(LL)fac[i-1]*i%mod;
}
}
LL power(LL a,LL b,LL c){
LL s=1,base=a%c;
while(b){
if(b&1) s=s*base%c;
base=base*base%c;
b>>=1;
}
return s;
}
LL inv(LL a){ // 費馬小定理求逆元
return power(a,mod-2,mod);
}
void solve(LL n){
LL ans=fac[n]; LL temp=1;
for(int i=1;i<=sz;i++){
LL cnt=0; LL t=n;
if(n/prm[i]){
while(t){
cnt+=t/prm[i];
t/=prm[i];
}
if(cnt&1) temp=temp*prm[i]%mod; // 將所有要除的先都存起來,最後求一下逆元, 一開始這裡直接就求逆元了,無限TLE。
}else break;
}
ans=ans*inv(temp)%mod; // 只要這裡求一次逆元就行了
printf("%lld\n",ans);
}
int main(){
LL n; init();
//printf("%d\n",sz);
while(scanf("%lld",&n)&&n){
solve(n);
}
return 0;
}