POJ 1845 Sumdiv(逆元的应用)

97 篇文章 0 订阅
47 篇文章 0 订阅

传送门

Sumdiv

Time Limit: 1000MSMemory Limit: 30000K
Total Submissions: 19009Accepted: 4773

Description

Consider two natural numbers A and B. Let S be the sum of all natural divisors of A^B.

Determine S modulo 9901 (the rest of the division of S by 9901).

Input

The only line contains the two natural numbers A and B, (0 <= A,B <= 50000000)separated by blanks.

Output

The only line of the output will contain S modulo 9901.

Sample Input

2 3

Sample Output

15

Hint

2^3 = 8.

The natural divisors of 8 are: 1,2,4,8. Their sum is 15.

15 modulo 9901 is 15 (that should be output).

Source



题目大意:

AB 的因子和对 MOD 取模。

解题思路:

首先 对 A 进行素因子分解:

A=pa11pa22...pakk

素因子分解完之后 AB 就等于

pa1B1pa2B2...pakBk

然后他们的素因子的和就可以写作:
ans=(1+p1+p21+...+pa1B1)((1+p2+p22+...+pa2B2))...(1+pk+p2k+...+pakBk)

每一个括号中的数是一个等比数列,然后等比数列求和得到:
ans=pa1B+11p11pa2B+12p21...pakB+1kpk1

现在我们要求的就是 ans%MOD ,但是 ans 带着分数,那么就要求逆元,可是这里有一个问

题是 逆元可能不存在,那么怎么办呢,我们就用到了一个公式:

AB%MOD=A%(MODB)B

根据这个公式就可以做了,首先要素数筛,然后素因子分解,快速幂,这里需要注意的是,当我们

进行快速幂的时候,中间有可能爆 long long 所以,在快速幂的过程中加上快速乘法,这样就可

以了。

My Code

/**
2016 - 08 - 08 下午
Author: ITAK

Motto:

今日的我要超越昨日的我,明日的我要胜过今日的我,
以创作出更好的代码为目标,不断地超越自己。
**/

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#include <set>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int INF = 1e9+5;
const int MAXN = 1e6+5;
const LL MOD = 9901;
const double eps = 1e-7;
const double PI = acos(-1.0);
using namespace std;
LL p[MAXN];
int k = 0;
bool prime[MAXN];
void isprime()
{
    k = 0;
    memset(prime, 0, sizeof(prime));
    prime[1] = 1;
    for(int i=2; i<MAXN; i++)
    {
        if(!prime[i])
        {
            p[k++] = i;
            for(int j=i+i; j<MAXN; j+=i)
                prime[j] = 1;
        }
    }
}
LL fac[MAXN/100], num[MAXN/100];
int cnt = 0;
void Dec(LL x)
{
    cnt = 0;
    memset(num, 0, sizeof(num));
    for(int i=0; p[i]*p[i]<=x; i++)
    {
        if(x%p[i] == 0)
        {
            fac[cnt] = p[i];
            while(x%p[i] == 0)
            {
                num[cnt]++;
                x /= p[i];
            }
            cnt++;
        }
    }
    if(x > 1)
    {
        fac[cnt] = x;
        num[cnt++] = 1;
    }
}
LL multi(LL a, LL b, LL c)
{
    LL ans = 0;
    while(b)
    {
        if(b & 1)
            ans = (ans+a)%c;
        b>>=1;
        a = (a+a)%c;
    }
    return ans;
}
LL quick_mod(LL a, LL b, LL c)
{
    LL ans = 1;
    while(b)
    {
        if(b & 1)
            ans = multi(ans, a, c);///可能爆 long long
        b>>=1;
        a = multi(a, a, c);
    }
    return ans;
}

int main()
{
    isprime();
    LL A, B;
    while(~scanf("%lld%lld",&A,&B))
    {
        Dec(A);
        LL ans = 1, x, y, tmp;
        for(int i=0; i<cnt; i++)
        {
            LL MM = MOD*(fac[i]-1);///MM * MM 容易爆 long long
            tmp = quick_mod(fac[i], num[i]*B+1, MM);
            tmp--;
            tmp = (tmp%MM+MM)%MM;
            tmp /= (fac[i]-1);
            ans = (ans*tmp)%MOD;
        }
        ans = (ans%MOD+MOD)%MOD;
        printf("%lld\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值