题目链接
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 \times c_i} \ }$的所有约数之和,按上面的式子化为等比数列后就是求$\prod {(p_i^{b \times 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 \times c_i}) \equiv B \times c_i+1$
真坑啊
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| #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; } } printf("%lld\n",ans); return 0; }
|