题目链接
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\)
真坑啊
代码
- #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\n",ans);
- return 0;
- }
来源: http://www.bubuko.com/infodetail-2767957.html