POJ1845Sumdiv题解--约数之和
Posted rye-catcher
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ1845Sumdiv题解--约数之和相关的知识,希望对你有一定的参考价值。
题目链接
https://cn.vjudge.net/problem/POJ-1845
分析
(POJ)里的数学题总是这么妙啊
首先有一个结论就是(A=prod{ {p_i}^{c_i} }),那么(A)所有约数之和为((1+p_1+p_1^2+..+p_1^{c_1}) * (1+p_2+p_2^2+...+p_2^{c_2}) ... (1+p_n +p_n^2 +... + p_n^{c_n}))
这个好像数学归纳法可证,但是感性理解一下也不难
于是这道题就是求(A^B = prod { {p_i}^{B imes c_i} })的所有约数之和,按上面的式子化为等比数列后就是求(prod {(p_i^{b imes c_i+1}-1)} / {(p_i-1) })
直接质因数分解后快速幂逆元即可
注意
虽然模数(9901)是个质数,但是这个数太小了,如果(p_i-1)是(9901)的倍数的话显然逆元都不存在了,但此时(p_i equiv 1 mod 9901),于是上述等比数列求和其实就是((1+1+1^2+1^3+...+1^{B imes c_i}) equiv B imes c_i+1)
真坑啊
代码
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cctype>
#define ll long long
#define ri register int
using std::min;
using std::max;
template <class T>inline void read(T &x){
x=0;int ne=0;char c;
while(!isdigit(c=getchar()))ne=c==‘-‘;
x=c-48;
while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48;
x=ne?-x:x;return ;
}
const int maxn= 100005;
const int inf= 0x7fffffff;
const ll p=9901;
int a,b;
int fac[maxn],cnt=0,ci[maxn];
inline void divide(int n){
for(ri i=2;i<=n;i++){
if(n%i)continue;
fac[++cnt]=i;
ci[cnt]=1;
n=n/i;
while(!(n%i)){n=n/i,ci[cnt]++;}
}
if(n>1){fac[++cnt]=n,ci[cnt]=1;}
return ;
}
int ksm(int x,ll c){
int ans=1;
while(c){
if(c&1)ans=1ll*ans*x%p;
x=1ll*x*x%p;
c=c>>1;
}
return ans;
}
int main(){
int x;
ll ans=1,y;
read(a),read(b);
divide(a);
for(ri i=1;i<=cnt;i++){
x=fac[i];
y=ci[i]*b;
if((x-1)%p==0){
ans=(y+1)%p*ans%p;
}
else{
ans=(ksm(x,y+1)%p-1+p)*ksm(x-1,p-2)%p*ans%p;
//注意+p,不然可能是负的
}
}
printf("%lld
",ans);
return 0;
}
以上是关于POJ1845Sumdiv题解--约数之和的主要内容,如果未能解决你的问题,请参考以下文章
Sumdiv POJ - 1845 A^b约数之和取模 内部递归 外部分治