【Sum(费马小定理+指数循环节公式)】

题目链接 HDU4704

【题意】就是求2^(n-1) % 1000000007 (n <= 10^100000)

【分析】由于n有100000位,所以直接快速幂也肯定超时,需要优化。

这里要使用到费马小定理;

费马小定理: gcd(a,m)=1(a,m互质) && m为素数,则a^(m-1)≡1 (mod m)

还需要用到一个公式(指数循环节):a^n  a^(n % Phi(M) + Phi(M)) (mod M) (n >= Phi(M));Phi(M)在M为素数时为M-1,n>=Phi(M)的限制可以不用考虑(当然考虑了不会有错,n<Phi(M)的话完全可以直接用快速幂了,我测试了几组数据结果都是一样的)。

有关这个公式的证明可以参考(数学渣表示看不懂)http://hi.baidu.com/aekdycoin/item/e493adc9a7c0870bad092fd9

这样在这里这个公式可以写成 a^n ≡ a^(n%(m-1)+m-1)  (mod m)(直接用这个公式复杂度已经很低了)

然后 因为1000000007是素数,并且gcd(2,1000000007) = 1,所以可以结合费马小定理化简上式:

a^n a^(n%(m-1)) * a^(m-1) a^(n%(m-1)) (mod m) 

这样求2^n-1 %1000000007只要求出(2^(n-1)%(1000000006)) %1000000007就可以了

【AC CODE(费马小定理+循环节公式)】0ms

#include <cstdio>
#include <cstring>
#include <cmath>
typedef long long LL;
#define MAXN 100010
#define MOD 1000000007
char c[MAXN];

int pow_mod(LL a, int n)
{
    LL ans = 1;
    while(n)
    {
        if(n&1) ans = ans*a%MOD;
        a = a*a%MOD;
        n >>= 1;
    }
    return ans;
}
int main()
{
#ifdef SHY
    freopen("e:\\1.txt","r",stdin);
#endif
    while(~scanf("%s%*c", c))
    {
        LL n = 0;
        for(int i = 0;c[i];i++)
            n = (n*10%(MOD-1)+c[i]-'0')%(MOD-1);
        printf("%d\n", pow_mod(2,(n-1+MOD-1)%(MOD-1)));
    }
    return 0;
}


 其实可以只用循环节公式a^(n%(m-1)) * a^(m-1)就能简化了

【AC CODE(循环节公式)】0ms

#include <cstdio>
#include <cstring>
#include <cmath>
typedef long long LL;
#define MAXN 100010
#define MOD 1000000007
char c[MAXN];

int pow_mod(LL a, int n)
{
    LL ans = 1;
    while(n)
    {
        if(n&1) ans = ans*a%MOD;
        a = a*a%MOD;
        n >>= 1;
    }
    return ans;
}
int main()
{
#ifdef SHY
    freopen("e:\\1.txt","r",stdin);
#endif
    while(~scanf("%s%*c", c))
    {
        LL n = 0;
        for(int i = 0;c[i];i++)
            n = (n*10%(MOD-1)+c[i]-'0')%(MOD-1);
        printf("%I64d\n", ((LL)pow_mod(2,(n-1+MOD-1)%(MOD-1))*pow_mod(2,MOD-1))%MOD);
    }
    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值