【OJ】POJ1845 (数学, a*b%mod, a^b%mod, a/b%mod, 分治, 逆元)

8 篇文章 0 订阅
3 篇文章 0 订阅

题目链接

Language:Default
Sumdiv
Time Limit: 1000MSMemory Limit: 30000K
Total Submissions: 28200Accepted: 6939

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

分析

A = p 1 a 1 × p 2 a 2 × p 3 a 3 × . . . × p n a n A = p_1^{a_1} \times p_2^{a_2} \times p_3^{a_3} \times...\times p_n^{a_n} \\ A=p1a1×p2a2×p3a3×...×pnan
A B = p 1 B × a 1 × p 2 B × a 2 × p 3 B × a 3 × . . . × p n B × a n A^B = p_1^{B \times a_1} \times p_2^{B \times a_2} \times p_3^{B \times a_3} \times...\times p_n^{B \times a_n} \\ AB=p1B×a1×p2B×a2×p3B×a3×...×pnB×an
A B = ( 1 + p 1 + p 1 2 + p 1 3 + . . . + p 1 B × a 1 ) × ( 1 + p 2 + p 2 2 + p 2 3 + . . . + p 2 B × a 2 ) × . . . × ( 1 + p n + p n 2 + p n 3 + . . . + p n B × a n ) A^B=(1+p_1+p_1^2+p_1^3+...+p_1^{B \times a_1} ) \times (1+p_2+p_2^2+p_2^3+...+p_2^{B \times a_2} ) \\\times ... \times(1+p_n+p_n^2+p_n^3+...+p_n^{B \times a_n} ) \\ AB=(1+p1+p12+p13+...+p1B×a1)×(1+p2+p22+p23+...+p2B×a2)×...×(1+pn+pn2+pn3+...+pnB×an)
设 s u m ( p , n ) = 1 + p + p 2 + p 3 + . . . + p n − 1 设 sum(p,n)=1+p+p^2+p^3+...+p^{n-1} \\ sum(p,n)=1+p+p2+p3+...+pn1
( 法 一 : 分 治 法 ) s u m ( p , n ) = ( 1 + p ⌊ n / 2 ⌋ ) × s u m ( p , ⌊ n / 2 ⌋ ) + ( n &VeryThinSpace; m o d &VeryThinSpace; 2 ) × p n − 1 (法一:分治法)\\ sum(p,n)=(1+p^{\lfloor n/2\rfloor})\times sum(p,{\lfloor n/2\rfloor})+(n \bmod 2) \times p^{n-1} sum(p,n)=(1+pn/2)×sum(p,n/2)+(nmod2)×pn1

LL sum(LL q, LL n, LL mod)
{
    if(n == 0)return 0ull;
    if(n == 1)return 1ull;
    LL ans = sum(q, n >> 1, mod), tmp = (1ull + pow_mod(q, n >> 1, mod)) % mod;
    if(1u & n)
        return ans = (mul_mod(ans, tmp, mod) + pow_mod(q, n - 1, mod)) % mod;
    else
        return ans = mul_mod(ans, tmp, mod);
}

( 法 二 : 除 法 取 模 , 逆 元 ) M = m × ( p − 1 ) s u m ( p , n ) &VeryThinSpace; m o d &VeryThinSpace; m = ( ( p n &VeryThinSpace; m o d &VeryThinSpace; M − 1 ) &VeryThinSpace; m o d &VeryThinSpace; M ) / ( p − 1 ) (法二:除法取模,逆元) \\ M= m \times (p-1) \\ sum(p,n) \bmod m =( (p^n \bmod M-1)\bmod M)/(p-1) ()M=m×(p1)sum(p,n)modm=((pnmodM1)modM)/(p1)

LL sum(LL q, LL n, LL mod)
{
    LL new_mod = (q - 1) * mod;
    LL numerator = pow_mod(q, n, new_mod) - 1;
    numerator = (numerator % new_mod + new_mod) % new_mod;
    return numerator / (q - 1);
}

主要公式在上面已经列举。快速幂,加减乘取模这种模板就不用多说了。另外还有一个质因数分解的模板,这个可以借助stl的vector+pair或者map。

代码

#include <iostream>
#include <vector>
#include <utility>

typedef long long LL;
using namespace std;

const LL mod = 9901;

LL mul_mod(LL a, LL b, LL mod)
{
    LL ans = 0;
    for(; b; b >>= 1)
    {
        if(1 & b)ans = (ans + a) % mod;
        a = (a << 1) % mod;
    }
    return ans;
}

//快速幂a^b,对mod取模,这是位运算版,且只适合非负数
LL pow_mod(LL a, LL b, LL mod)
{
    LL ans = 1 % mod;
    for(; b; b >>= 1)
    {
        if(1 & b)ans = mul_mod(ans, a, mod);
        a = mul_mod(a, a, mod);
    }
    return ans;
}

//质因数分解
//x>=2
vector<pair<LL,LL> > get_prime_factors(LL x)
{
    vector<pair<LL, LL> > prime_factors;
    for(LL i = 2; i*i<=x; i++)
    {
        if(x % i)continue;
        LL cnt = 0;
        while(x % i == 0)
        {
            x /= i;
            cnt++;
        }
        prime_factors.push_back(make_pair(i, cnt));
    }
    //注意,最后可能会留一个大于n^(1/2)的质数,n为x原本的大小
    //例如14=2*7
    if(x!=1)prime_factors.push_back(make_pair(x,1));
    return prime_factors;
}

/*
//一种map版的写法
//
//map使用[]时,复杂度为O(logn)
//如果没有元素,会先自动生成一个二元组
//自动生成的value为zero(0,""等)

map<LL,LL> prime_factor(LL n)
{
    map<LL,LL> res;
    for(LL i=2;i*i<=n;i++)
        while(n%i==0) {++res[i];n/=i;}
    if(n!=1) res[n]=1;
    return res;
}
*/

等比数列求和,对mod取模

//除法取模版(或者说时逆元版,虽然没有逆元)
//1+q+...+q^(n-1)=(q^n-1)/(q-1)
//(a/b)%m = (a%(b*m))/b
LL sum(LL q, LL n, LL mod)
{
    LL new_mod = (q - 1) * mod;
    LL numerator = pow_mod(q, n, new_mod) - 1;
    numerator = (numerator % new_mod + new_mod) % new_mod;
    return numerator / (q - 1);
}

/*
//二分版
//(由于mod只对加、减、乘有分配率,所以涉及到取模的,不能直接用等比数列求和公式)
//首项a0,公比q,项数n,模mod,不过这里a0就是1,所以不用管
LL sum(LL q, LL n, LL mod)
{
    if(n == 0)return 0ull;
    if(n == 1)return 1ull;
    LL ans = sum(q, n >> 1, mod), tmp = (1ull + pow_mod(q, n >> 1, mod)) % mod;
    if(1u & n)
        return ans = (mul_mod(ans, tmp, mod) + pow_mod(q, n - 1, mod)) % mod;
    else
        return ans = mul_mod(ans, tmp, mod);
}
*/

LL get_ans(LL A, LL B, LL mod)
{
    if(A == 0)return 0;
    else if(A == 1 or B == 0)return 1 % mod;
    vector<pair<LL,LL> > prime_factors = get_prime_factors(A);
    LL ans = 1ll;
    for(vector<pair<LL,LL> >::iterator it = prime_factors.begin(); it != prime_factors.end(); it++)
    {
        LL q = it->first, c = it->second;
        LL tmp = sum(q, c * B + 1, mod);
        ans = mul_mod(ans, tmp, mod);
    }
    return ans;
}

int main()
{
    LL A, B;
    cin >> A >> B;
    LL ans = get_ans(A, B, mod);
    cout << ans << endl;
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值