ACM: 一道累加同余求模 poj1845  (…

本文介绍了一种解决特定数学问题的高效算法,该问题要求计算一个数的幂次方的所有因子之和,并对结果进行模运算。通过质因数分解和快速幂技巧,实现了对大规模数据的有效处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

Sumdiv

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

题意: 输入A , B. 求 A^B所有因子的和 mod 9901

个人思路:

1.规模大,同余求模,归类为数论题.

2.回忆三个公式: (递推的关键)

(a+b) mod n = ((a mod n) + (b mod n)) mod n ①

(a-b) mod n = ((a mod n) - (b mod n) + n) mod n ②

ab mod n = (a mod n) (b mod n) mod n ③

3.天真的想法: 二分 a^n 对 m 求余后 , 用公式①暴力求解(0~n) 题意弄错了.

题意是求A^B得因子的累加和.

纠正后发现:

排列组合的思维: A^B的因子的和. 设p1,p2,p3...pn是A得质因子.

推出公式: (p1^0+p1^1+...p1^B)*(P2^0+P2^1+...+P2^B)*...*(pn^0+pn^1+...+pn^B)

 

网上发现:

计算 1 + P + P^2 + P^3 +...+ P ^B 可用二分求解;

当k是偶数时: 例如k=4,1 + P + P^2 + P^3 + P^4 = (1+P) + P^2 * (1+P*(1+P));

当k是奇数时: 例如k=5,1 + P + P^2 + P^3 + P^4 + P^5 = (1 + P + P^2) + P^3 * (1 + P + P^2);

(两次二分速度就很快乐了!!)

代码:

#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
#define mod 9901
#define MAX 100005

int a[MAX] = {0}; //个数
int b[MAX] = {0}; //因子

__int64 pow_mod(__int64 a,__int64 n)
{
       if(n == 0)
             return 1;
       __int64 t = pow_mod(a,n/2);
       __int64 ans = (__int64) t * t % mod;
       if(n % 2 == 1)
             ans = ans * a %mod;
       return ans;
}

__int64 sum(__int64 a,__int64 n)
{
        if(n==0) 
            return 1;  
        if(n % 2 == 1)       //n % 2 == 1;  
            return (((1 + pow_mod(a,n/2+1)) % mod) * (sum(a,n/2) % mod)) % mod; 
        else  
     return (((1 + pow_mod(a,n/2+1)) % mod) * (sum(a,(n-1)/2) % mod) + pow_mod(a,n/2) % mod) % mod; 
}

int main()
{
       __int64 A , B;

while(scanf("%I64d %I64d",&A,&B) != EOF)
      {
           memset(a,0,sizeof(a));
           memset(b,0,sizeof(b));
           int i;
           int num = 0;
           for(i = 2; i*i <= A; ++i)
          {
                if(A % i == 0)
               {
                     a[++a[0]] = i;
                     while(A % i == 0)
                    {
                             A /= i;
                             b[a[0]]++;
                     }
                }
           }

if(A != 1)
        {
              a[++a[0]] = A;
              b[a[0]]++;
        }

__int64 result = 1;
          for(i = 1; i <= a[0]; ++i)
         {
                result = ((result % mod) * (sum(a[i], b[i]*B)) % mod) % mod; 
          }
           printf("%I64d\n",result);
      }

return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值