求每个数字的约数和约数个数,假设约数为$p$,约数最多$k$个
那么我们要用一种排列组合的思想去做(细节不阐述了)
$p^0+p^1+p^2+p^3+…+p^k$
对每个数的约数都如此操作,然后乘到最后的答案里去
问题在于对每个$p$都做一遍$O(k)$的算法很浪费时间
所以我们用分治的思想去简化
假设k为奇数
公式可以转化为$sum(p,k)=(1+p^\frac{k}{2})*sum(p,\frac{k-1}{2})$
如果k为偶数的话,我们可以投机取巧地将它变成奇数
$sum(p,k)=sum(p,k-1)+p^k$
最后所有的$p^\frac{k}{2}$或$p^k$用取模快速幂做就可以了
复杂度就被下降为了$O(logk)$的级别
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
| #include <iostream> using namespace std; const int mod=9901;
int qmi(int a,int b,int p){ int ans=1; while(b){ if(b&1) ans=ans*1ll*a%p; b>>=1; a=a*1ll*a%p; } return ans%p; }
int sum(int p,int k){ if(k==0) return 1; else if(k&1) return sum(p,(k-1)/2)*1ll*(qmi(p,(k+1)/2,mod)+1)%mod; else return (sum(p,k/2-1)*1ll*(qmi(p,k/2,mod)+1)%mod+qmi(p,k,mod))%mod; }
int main(){ int a,b,ans=1; scanf("%d%d",&a,&b); for(int i=2;i<=a/i;i++){ if(a%i==0){ int s=0; while(a%i==0) a/=i,s++; ans=ans*1ll*sum(i,s*b)%mod; } } if(a>1) ans=ans*1ll*sum(a,b)%mod; if(a==0) ans=0; printf("%d\n",ans); return 0; }
|