hdu-1452(约数和定理+求逆元)

问题描述:

Consider a positive integer X,and let S be the sum of all positive integer divisors of 2004^X. Your job is to determine S modulo 29 (the rest of the division of S by 29). 

Take X = 1 for an example. The positive integer divisors of 2004^1 are 1, 2, 3, 4, 6, 12, 167, 334, 501, 668, 1002 and 2004. Therefore S = 4704 and S modulo 29 is equal to 6. 

Input

The input consists of several test cases. Each test case contains a line with the integer X (1 <= X <= 10000000). 

A test case of X = 0 indicates the end of input, and should not be processed.

Output

For each test case, in a separate line, please output the result of S modulo 29.

Sample Input

1
10000
0
Sample Output

6
10

题目题意:题目给我们一个让我们求出2004^x的所有的约数和,然后%29.

题目分析:这个题目就是考到了一个定理(约数和定理),数论的题目考的范围很广(定理很多,所以得多做题目,多总结),下面是百度对约数和定理的解释。

对于一个大于1正整数n可以分解质因数:n=p1^a1*p2^a2*p3^a3*…*pk^ak,

则由约数个数定理可知n的正约数有(a₁+1)(a₂+1)(a₃+1)…(ak+1)个

那么n的(a₁+1)(a₂+1)(a₃+1)…(ak+1)个正约数的和为

f(n)=(p1^0+p1^1+p1^2+…p1^a1)(p2^0+p2^1+p2^2+…p2^a2)…(pk^0+pk^1+pk^2+…pk^ak)。

知道到了这个定理,是不是就明了了。

2004=2^2*3*167

则2004^x=2^(2*x)*3^(x)*167^(x).

我们由公式展开:

f(x)=(2^0+2^1+2^2+2^3+.....+2^(2*x))*(3^0+3^1+3^2+3^3+....+3^x)*(167^0+167^1+167^2+167^3+.........+167^x)

又等比公式求和公式可以化简得:

f(x)=(2^(2*x+1)-1)*(3^(x+1)-1)*(167^(x+1)-1)/332%29.

存在除法取余,那么肯定得求逆元。


一开始我用了费马小定理,错了!!!是自己没有注意各种求逆元方法范围,下面写了各种求逆元方法和范围。

对于同于方程ax=1 mod m 当gcd(a,m)==1时那么肯定存在x等于1/a  mod m即x 就是a在模数为m下的逆元.

方法一:扩展欧几里得法:

我们对同余方程ax=1 mod m

即ax +my=1 求解这个同余方程即可。

方法二:费马小定理:

 假如p是质数,且gcd(a,p)=1,那么 a(p-1)≡1(mod p)

我们变形:即a*a^(p-2)=1 mod p 那么a^(p-2)=1 /a mod p

即a^(p-2) 为逆元,注意p要是质数

方法三:欧拉定理法:

数论中,欧拉定理,(也称 费马-欧拉定理)是一个关于同余的性质。欧拉定理表明,若n,a为 正整数,且n,a 互质,则:
我们变形:即a^(phi(n)-1)= 1 /a mod n 为逆元。
方法四:线形打表求逆元
当模数p为质数时:

Inv[i]=inv[mod%i]*(mod-mod/i)%mod; (其中inv[i]保存的是i的逆元,复杂度为o(n)),证明可以百度搜一下.

好了,我知道的就这么多了。

这道题目的代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;

const int mod=29;

int exgcd(int a,int b,int &x,int &y)
{
    if (b==0) {
        x=1;
        y=0;
        return a;
    }
    int r=exgcd(b,a%b,x,y);
    int t=x;
    x=y;
    y=t-a/b*y;
    return r;
}
bool linear_equation(int a,int b,int c,int &x,int &y)
{
    int d=exgcd(a,b,x,y);
    if (c%d)
        return false;
    int k=c/d;
    int t=b/d;
    x=x*k,y=y*k;
    x=(x%t+t)%t;
    return true;
}
int fast_pow(int base,int k)
{
    int ans=1;
    while (k) {
        if (k&1)
            ans=ans*base%mod;
        base=base*base%mod;
        k>>=1;
    }
    return ans;
}
int main()
{
    int x,inv,k1,k2;
    linear_equation(332,mod,1,k1,k2);//扩展欧几里得,求逆元
    inv=k1;
    while (scanf("%d",&x)!=EOF) {
        if (x==0) break;
        int ans=1;
        ans=ans*(fast_pow(2,2*x+1)-1)%mod;
        ans=ans*(fast_pow(3,x+1)-1)%mod;
        ans=ans*(fast_pow(167,x+1)-1)%mod;
        ans=ans*inv%mod;
        printf("%d\n",ans);
    }
    return 0;
}




 













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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值