循环节 (模取幂运算)

计算a^(n!) mod c(原创转载请注明)
什么是循环节?
https://i-blog.csdnimg.cn/blog_migrate/5704d66a090face25597db5b6dafaba5.jpeg
那么满足条件的最小的b称为循环节开始位置
满足条件的最小的正整数为T称为循环节长度(T>0)

首先通过下面的程序可以很容易的验证
1..106的数,他的循环节不超过106
#include<iostream>
using namespace std;
const int C=107;
int hash[1000001];
int main()
{
    int n,sp,len,i,tmp;
    for(n=1;n<=106;n++)
    {
        memset(hash,0,sizeof(hash));
        hash[n%C]=1;
        tmp=n;
        for(i=2;;i++)
        {
            tmp*=n;
            tmp%=C;
            if(hash[tmp%C])break;
        }
        cout<<n<<':'<<hash[tmp%C]<<' '<<i-hash[tmp%C]<<endl;
    }
    return 0;
}
并且循环节的开始位置都是1。
当然这个只是对于比较特殊的数如107才满足开始位置为1,如果对于任意的数,那么循环节的开始位置不一定是1。
下面讨论一般情况
假设a^b mod c的循环节是len,开始位置是spos
定义一个操作op()取得k
0.op(b)
1.if b<spos then k=b
2. else k=spos+(b-spos)%len

最后计算a^k mod c既可
这样可以极大的简化问题,使得b的规模 大幅度减小
下面介绍下如何求a^(n!) mod c
有了上面的方法,我相信你们都想到了吧,就是求a^op(n!) mod c
下面开始讨论
op(n!)
if n!<spos k=n!//通常spos很小
else k=spos+(n!-spos)%len= spos+((n!)%len-spos%len+len)%len
问题又转化为求n!%len
那么
1.n>=len n!%len= 0
2.n<len
https://i-blog.csdnimg.cn/blog_migrate/fdd8a88ef612d85566f5eed73e7eafad.jpeg
当然了过程中不要忘记取mod


当C比较大的时候怎么求循环节?下面给出一个方法
1.令W=C//想想为什么?
2.解模方程 https://i-blog.csdnimg.cn/blog_migrate/e9d181e20ca0d07094a762cac0e13ede.jpeg
求得最大的b,b为开始位置,w-b为循环节长度

可是当w-b非常大,n却<w-b的时候,复杂度变成了o(n)...若n过大可能导致超时.
下面的问题就转化成能否快速计算n! % c 类型的问题了

表示没看懂~~~~~~~

 

a^bmod n 。logn算法

int modexp(int a,int b,int n)

{

        int t=a,ret=1;

        whilie(b!=0){

        if(b%2 == 1) ret*=t%n;

             b/=2;

}

return ret;

}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值