您的位置:首页 > 其它

POJ 1845 Sumdiv 解题报告(二分 & 逆元)

2013-08-06 21:47 375 查看
    题目大意:求A^B 所有因数和。

    解题报告:公式就不推了,这个链接有详细的推理过程:http://blog.csdn.net/lyy289065406/article/details/6648539

    可以使用二分来求(p^0+p^1+p^2+……+p^n),道理也很简单前一半乘以p^(n/2)就等于后一半,注意奇偶就好了。二分比较好想到,也容易实现,但是用逆元可以更快的求解。

    何为逆元?我也说不清,百度一下就有相关解释的。简单来说就是我想求得 ((p^(n+1)-1)/(p-1))%MOD,我可以求得(p-1)关于模MOD的逆元t后,直接计算 ((p^(n+1)-1)*t)%MOD。当然这个结果可能是负数(p==MOD),所以最后判断一下就好了。

    关于逆元的更多知识就百度吧,笔者也是刚接触。学习了大牛的代码,AC代码如下:

#include <cstring>
#include <cstdio>
#include <time.h>
#include <bitset>
using namespace std;

const int MOD = 9901;
int val[1000];
int num[1000];
int top;

void gcd(int a, int b, int & x, int & y)
{
if (b == 0)
{
x = 1;
y = 0;
}
else
{
gcd(b, a%b, y, x);
y -= (a / b) * x;
}
}

int inv(int a)
{
int x, y;
gcd(a, MOD, x, y);
return x % MOD;
}

int powMod(int a, int b)
{
a %= MOD;
int res = 1;
while (b)
{
if (b & 1)
res = res * a % MOD;
b >>= 1;
a = a * a % MOD;
}
return res;
}

void work()
{
int a, b;
scanf("%d%d", &a, &b);

for (int i = 2; i*i <= a; i++)
{
int t = 0;
while (a%i == 0)
{
a /= i;
t++;
}
if (t)
{
val[top] = i;
num[top] = t;
top++;
}
}

if (a != 1)
{
val[top] = a;
num[top] = 1;
top++;
}

int res = 1;
for (int i = 0; i < top; i++)
{
if ((val[i] - 1) % MOD == 0)
{
/* 如果此时val[i]-1是素数9901的整数倍,假设a = val[i],则 (a-1) mod 9901 = 0
a^0 + a^1 + a^2 + ... + a^n = 1 + ... + (a-1)^n + (a-1)^(n-1) + ... + (a-1)^0 = n + 1
所以可以得出以下式子
*/
res = (res * (num[i] * b % MOD + 1)) % MOD;
}
else
{
int x = inv(val[i] - 1);
/*
2^31 = 2147483647, 所以num[i]<31, 所以 num[i]*b 不会超int
*/
res = (res * (powMod(val[i], num[i] * b + 1) - 1) % MOD * x) % MOD;
}
}

printf("%d\n", (res + MOD) % MOD);
}

int main()
{
work();
}


    二分的代码如下:

#include <cstdio>
#include <cstring>
#define LL long long
const int MOD=9901;

int val[MOD];
int num[MOD];

int QPower(int p,int n)
{
p%=MOD;
int res=1;
while(n)
{
if(n&1)
res=(res*p)%MOD;
p=(p*p)%MOD;
n>>=1;
}
return (int)res;
}

int sum(LL p,LL n)
{
if(n==0)
return 1;
if(n&1)
return ((LL)sum(p,n/2)*(1+QPower(p,n/2+1)))%MOD;
else
return ((LL)sum(p,n/2-1)*(1+QPower(p,n/2+1))+QPower(p,n/2))%MOD;
}

int main()
{
int a,b;
scanf("%d%d",&a,&b);
int index=2;
int pNum=0;

while(a>1)
{
int n=0;
while(a%index==0)
{
n++;
a/=index;
}
if(n)
{
val[pNum]=index;
num[pNum]=n;
pNum++;
}
index++;
}

int ans=1;
for(int i=0;i<pNum;i++)
ans=((LL)ans*sum(val[i],(LL)num[i]*b))%MOD;
printf("%d\n",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  逆元 数论