快速幂求模 和 费马小定理

hdu 1061

纯快速幂


hdu 3033

这题的大意是:一种动物身上有n种不同的皮肤,每种皮肤有透明很不透明两种状态,经过一天的日晒,透明的可以变成不透明,不透明的可以变成透明,但是需要注意的是,如果皮肤的外层是透明的话,阳光可以照射到内层,如果是不透明的话,则不可以。

然后刚出生的动物身上的皮肤都是不透明的,问多少天后,全部的皮肤都变过透明的。。
递推公式:res=(2^(n-1)+1)mod(n) 


hdu 4196

题目:用不大于n内的所有数去组成一个尽可能大的完全平方数。

完全平方数,显然是所有的素因子的个数都是偶数,便取N!的所有素因子的个数,便 有了初步想法,算出N!的什么素因子个数,奇数的就舍去一个,偶数的全要,然后再全部乘起来,可是因为规模很大,即使快速幂乘也是会超时。

于是考虑把N!除掉那些奇数个因子的乘积,便是求a=c/b,由于是取模的,直接除必然不行。

考虑c%mod=(a%mod)*(b%mod);令A=a%mod; B=b%mod;C=c%mod;

则A=a%mod=(a*1)%mod=a%mod*1%mod=(a%mod)*(b^(mod-1))%mod --------因为(b^(mod-1))%mod=1,费马小定理。

=(a*b)%mod*(b^(mod-2))%mod=(c%mod)*(b%mod)^(mod-2)%mod=C*B^(mod-2)

利用这个,就可以求出c/b的结果。

(PS:product 翻译为 乘积!)

代码:


#include <stdio.h>
#include <math.h>
#define N 10000001
#define M 3000000
#define MOD 1000000007
__int64 fac[N];
int pri[N];
int cnt;
void p()
{
    fac[0] = 1;
    int i,j;
    for(i = 1; i < N; ++i)
        fac[i] = i * fac[i-1] % MOD;

    int n = sqrt(N*1.0);
    for(i = 2; i <= n; ++i)
        if(!pri[i])
            for(j = i * i; j < N; j += i)
                pri[j] = 1;
    for(i = 2; i < N; ++i)
        if(!pri[i])
            pri[cnt++] = i;
}
__int64 fastPow(__int64 p,int d)
{
    __int64 ans = 1;
    while(d)
    {
        if(d&1)
            ans = (ans * p) % MOD;
        d >>= 1;
        p = (p * p) % MOD;
    }
    return ans;
}
int getSum(int n,int p)  //这是求n!中质因子p的幂的次数
{
    int sum = 0;
    while(n)
    {
        sum += n/p;
        n /= p;
    }
    return sum;
}
int main()
{
    p();
    __int64 b;
    int n,i;
    while(scanf("%d",&n) == 1 && n)
    {
        b = 1;
        for(i = 0; i < cnt && pri[i] <= n; ++i)
        {
            if((getSum(n,pri[i])) & 1)
                b = b * pri[i] % MOD;
        }
        printf("%I64d\n",fac[n]*fastPow(b,MOD-2)%MOD);
    }
    return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值