POJ1845:Sumdiv(求因子和+逆元+质因子分解)好题

题目链接:http://poj.org/problem?id=1845

定义: 满足a*k≡1 (mod p)的k值就是a关于p的乘法逆元。

为什么要有乘法逆元呢?

当我们要求(a/b) mod p的值,且a很大,无法直接求得a/b的值时,我们就要用到乘法逆元。 我们可以通过求b关于p的乘法逆元k,将a乘上k再模p,

即(a*k) mod p。其结果与(a/b) mod p等价。

题目解析:让求a^b的因子和modk,因为是大数没法直接求,因为求因子和函数是乘性函数,所以首先要质因子分解,化成n=p1^a1*p2^a2*p3^a3****Ps^as,那么

s(n)=[(p1^a1+1 -1)/(p1-1)]*[(p2^a2+1 -1)/(p2-1)]*[(p3^a3+1 -1)/(p3-1)]***[(ps^as+1 -1)/(ps-1)];(因子和)

又因为s(n)%mod等于每一个部分取模,所以可以逐步求解,如求(p1^a1+1  -1)/(p1-1)%mod,在这里就要运用除法取模所以要用到乘法逆元的概念,

即(a/b) %p= ( a *b^(-1)%p) ,又因为(a^b) % p = ((a % p)^b) % p ,

所以(p1^a1+1  -1)/(p1-1)%mod==(((p1%mod)^a1+1 -1)%mod*(p1-1)^-1)%mod;

当然存在逆元的前提是gcd(a,p)==1;

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
#define N  500010
#define mod 9901
typedef __int64 ll;
using namespace std;
ll a,b,X,Y;
ll ans[N],num[N],top;
ll pow(ll x,ll k)
{
    ll t=1;
    while(k)
    {
        if(k&1) t=((t%mod)*(x%mod))%mod;
        k>>=1;
        x=((x%mod)*(x%mod))%mod;
    }
    return t;
}
void extend(__int64 A,__int64 B,__int64 &x1, __int64 &y1)
{
    if(B==0)
    {
        x1=1;
        y1=0;
        return ;
    }
    extend(B,A%B,x1,y1);
    ll t=x1;
    x1=y1;
    y1=t-(A/B)*y1;
    return ;
}
void solve()
{
    ll sum=1,A,xx;
    for(int i=0; i<top; i++)
    {
        if(ans[i]%mod==0) continue;//关键的两个判断,关系到求逆元。 如果ans[i]%mod=0,那么有等级公式可以看出,原式小于0,所以也只能利用原式求,结果为1
        if(ans[i]%mod==1)//即mod|(ans[i]-1),因为ans[i]>=2,所以ans[i]不可能等于1,这是gcd(ans[i]-1,mod)==mod,不存在逆元,无法利用扩展欧几里得求逆元
        {                                  //这时为(1+ans[i]^1+ans[i]^2+.....+ans[i]^num[i])%mod=(num[i]+1)%mod;
            sum=(sum*(num[i]+1))%mod;
            continue;
        }
        A=pow(ans[i],num[i]+1);
        A=(A-1)%mod;
        extend(ans[i]-1,mod,X,Y);//因为ans[i]为素数,ans[i]-1为偶数,所以ans[i]-1与9901互质
        xx=(X%mod+mod)%mod;
        A=((A%mod)*(xx%mod))%mod;
        sum=(sum*A)%mod;
    }
    printf("%I64d\n",sum);
}
int main()
{
    while(scanf("%I64d%I64d",&a,&b)!=EOF)
    {
        if(a==0)
        {
            printf("0\n");
            continue;
        }
        else if(a==1||b==0)
        {
            printf("1\n");
            continue;
        }
        ll t=a;
        top=0;
        memset(num,0,sizeof(num));
        for(int i=2; i*i<=a; i++)
        {
            if(t%i==0)
            {
                num[top]++;
                ans[top]=i;
                t/=i;
                while(t%i==0)
                {
                    num[top]++;
                    t/=i;
                }
                top++;
            }
        }
        if(t>1)
        {
            num[top]++;
            ans[top++]=t;
        }
        for(int i=0; i<top; i++)
        {
            num[i]*=b;
        }
        solve();
    }
    return 0;
}
时间: 2024-08-04 05:24:11

POJ1845:Sumdiv(求因子和+逆元+质因子分解)好题的相关文章

HDU1452:Happy 2004(求因子和+分解质因子+逆元)上一题的简单版

题目链接:传送门 题目要求:求S(2004^x)%29. 题目解析: #include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> #include <math.h> #define mod 29 using namespace std; typedef long long ll; ll mpow(ll x,ll k) { ll t=1; while

hdu5392--Infoplane in Tina Town(置换群+质因子分解求最小公倍数)

题目链接:点击打开链接 题目大意:给出一种操作a[1],a[2],,,,a[n],代表每交换一次,1位置的数到a[1]位置,2位置的数到a[2]位置,,, 问最终交换多少次可以恢复初始的情况. 题目给出一个置换,要求置换的次数,也就是所有轮换个数的最小公倍数.首先求出所有轮换的个数,然后求最小公倍数的时候不能用gcd,因为Mod的取余太大,所以用质因子分解,统计每个质因子出现的最多次数,计算最终的值. #include <cstdio> #include <cstring> #in

POJ1845 Sumdiv - 乘法逆元+快速幂【A^B的约数个数和】

POJ1845 Sumdiv Sol: 约数个数和\(sumdiv=(1+p_1+p_1^2+\dots + p_1^{c_1})*\dots *(1+p_k+p_k^2+\dots + p_k^{c_k})\) 其中每一项都是一个首项为1,公比为\(p_i\)的等比数列的和,即 \(1*\frac{1-p_i^{c_{k}+1}}{1-p_i}=\frac{p_i^{c_{k}+1}-1}{p_i-1}\) 可以通过快速幂+逆元求解. 然而,当\(9901|(p_i-1)\)时,\(p_i-1

求一个数的质因子

private static void prime(int i){ int j = 2; while(true){ while(i%j == 0 && i != j){ System.out.println("Prime num " + j); i = i/j; } if(i == j){ System.out.println("Prime num " + j); break; } j++; } } private static void prime

[ACM] POJ 1845 Sumdiv(求A的B次方的所有因子的和,一大堆数学公式...,可做模板)

Sumdiv Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 13792   Accepted: 3399 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 99

BZOJ 1485: [HNOI2009]有趣的数列 [Catlan数 质因子分解]

1485: [HNOI2009]有趣的数列 Description 我们称一个长度为2n的数列是有趣的,当且仅当该数列满足以下三个条件: (1)它是从1到2n共2n个整数的一个排列{ai}: (2)所有的奇数项满足a1<a3<…<a2n-1,所有的偶数项满足a2<a4<…<a2n: (3)任意相邻的两项a2i-1与a2i(1≤i≤n)满足奇数项小于偶数项,即:a2i-1<a2i. 现在的任务是:对于给定的n,请求出有多少个不同的长度为2n的有趣的数列.因为最后的答

uva10780 质因子分解

UVA - 10780 Again Prime? No Time.(uva卡得一逼,所以还是把vj的链接贴一下把) 题意:给出n,m,使得m^k是n!的因子,求最大的k 思路:质因子分解,将m 和n!都分解为 p1^a1*p2^a2*...pn^an,其中p1 p2...pn是连续的质数2,3,5,7...,用一个数组记录每个质数的次幂ai,然后二分答案k,只有当m分解的质因子的次幂*k全部小于等于n!分解的质因子次幂,m^k才是n!的因子,比较坑的一点是,当k=0时是作为无解的情况的 AC代码

hdoj 1492 The number of divisors(约数) about Humble Numbers 【数论】【质因子分解 求和】

定理:一个正整数 n 可以用素因子唯一表示为 p1^r1 * p2^r2 * ... pk^rk (其中 pi 为素数) , 那么这个数的因子的个数就是,(r1+1)*(r2+1)*...*(rk+1). 理解:为什么是加1之后再相乘,因为一个数的的因子数至少为1和他自身,但因为r1,r2..可以为0,所以因子的个数为(r1+1)... 拓展一下: 定理1: 一个正整数 n 可以用素因子唯一表示为 p1^r1 * p2^r2 * ... pk^rk (其中 pi 为素数) , 那么这个数的因子的

HDU 2601 An easy problem(暴力枚举/质因子分解)

An easy problem Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 7963    Accepted Submission(s): 1920 Problem Description When Teddy was a child , he was always thinking about some simple math p