【HDU - 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值