POJ 1845(数论 模运算)

    首先需要知道正整数的唯一分解式:

N=(p1^a1)*(p2^a2)*.........*(pn^an);

  那么N的所有因子之和为(1+p1+p1^2+.....+p1^a1)*(1+p2+p2^2+.......+p2^a2)*......(1+pn+pn^2+.....pn^an);

那么怎么去求p1,.....pn,a1......an的值呢?猛戳 http://blog.csdn.net/u014686462/article/details/37889583 讲的不能再详细了。

  另外就是要求所有因子的和了,注意这里不能直接用等比数列公式,因为它不满足模运算,所以就采用了二分递归求和。据说也可以用求逆元来求和,待会研究研究。

代码:

#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long LL;
const int MOD=9901;
int N;
LL p[1000],num[1000];
LL  exp_mod(LL a,LL b)
{
    LL ans=1;
    a%=MOD;
    while(b)
    {
        if(b&1) ans=(ans*a)%MOD;
        a=(a*a)%MOD;
        b>>=1;
    }
    return ans;
}
LL sum(LL p,LL n)
{
    if(n==0)
        return 1;
    if(n%2)
        return (sum(p,n/2)*(1+exp_mod(p,n/2+1)))%MOD;
    else
        return (sum(p,n/2-1)*(1+exp_mod(p,n/2+1))+exp_mod(p,n/2))%MOD;
}
void ph(LL x)
{
    N=0;
    memset(p,0,sizeof(p));
    memset(num,0,sizeof(num));
    for(LL i=2;i<(LL)sqrt(1.0*x)+1;i++)
    {
        if(x%i==0)
        {
            while(x%i==0)
            {
                num[N]++;
                x/=i;
            }
            p[N++]=i;
        }
    }
    if(x>1)  num[N]++,p[N++]=x;
}
int main()
{
    LL a,b;
    while(cin>>a>>b)
    {
        if(a==0)  puts("0");
        else
        {
            ph(a);
        //for(int i=0;i<N;i++)
          //  printf("%d %d\n",p[i],num[i]);
           LL ans=1;
           for(int i=0;i<N;i++)
           {
               ans=(ans*(sum(p[i],b*num[i])%MOD))%MOD;
           }
           cout<<ans<<endl;
        }
    }
    return 0;
}

  用逆元的做法:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<stack>
using namespace std;
typedef long long LL;
const LL M=9901;
LL p[1000],num[1000];
int N;
LL exp_mod(LL a,LL b)
{
   LL ans=1;
   a%=M;
   while(b)
   {
       if(b&1) ans=(ans*a)%M;
       a=(a*a)%M;
       b>>=1;
   }
   return ans;
}
void phi(LL x)
{
        N=0;
        memset(p,0,sizeof(p));
        memset(num,0,sizeof(num));
        for(LL i=2;i<(LL)sqrt(1.0*x)+1;i++)
        {
            if(x%i==0)
            {
                while(x%i==0)
                {
                    num[N]++;
                    x/=i;
                }
                p[N++]=i;
            }
        }
        if(x>1)  num[N]++,p[N++]=x;
}
int main()
{
    freopen("in.txt","r",stdin);
    LL a,b;
    while(cin>>a>>b){
         if(a==0) puts("0");
         else
         {
             phi(a);
             LL ans=1;
             for(int i=0;i<N;i++)
             {
                if(p[i]%M==0) continue;
                if(p[i]%M==1)
                {
                    ans=ans*(num[i]*b+1)%M;
                    continue;
                }
                LL c=exp_mod(p[i]-1,M-2);
                ans=(ans*(c*(exp_mod(p[i],b*num[i]+1)-1+M)%M)%M)%M;
             }
             cout<<ans<<endl;
         }
    }
    return 0;
}


<span style="color:#FF0000;">if(p[i]%M==0) 
if(p[i]%M==1)</span>
这两个特判一定要注意!!!



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值