题解 poj1845 Sumdiv (数论) (分治)
大意:求A^B的所有因子之和,并对其取模 9901再输出
(这题又调了半天,把n和项数弄混了QAQ)
根据算数基本定理:A=(p1^k1)*(p2^k2)*(p3^k3)*...*(pn^kn) (pi为素数)
则A的所有因子之和Sum=(1+p1+p1^2+p1^3+...p1^k1) * (1+p2+p2^2+p2^3+….p2^k2) * (1+p3+ p3^3+…+ p3^k3) * .... * (1+pn+pn^2+pn^3+...pn^kn)
那么A^B = p1^(k1*B) * p2^(k2*B) * p3^(k3*B) *...* pn^(kn*B)
所以Sum=[1+p1+p1^2+...+p1^(a1*B)] * [1+p2+p2^2+...+p2^(a2*B)] *...* [1+pn+pn^2+...+pn^(an*B)]
用分治求等比数列1+pi+pi^2+pi^3+...+pi^n:
(1)若n为奇数(有偶数项)则:
1 + p + p^2 + p^3 +...+ p^n
= (1+p^(n/2+1)) + p * (1+p^(n/2+1)) +...+ p^(n/2) * (1+p^(n/2+1))
= (1 + p + p^2 +...+ p^(n/2)) * (1 + p^(n/2+1))
(2)若n为偶数(有奇数项)则:
1 + p + p^2 + p^3 +...+ p^n
= (1+p^(n/2+1)) + p * (1+p^(n/2+1)) +...+ p^(n/2-1) * (1+p^(n/2+1)) + p^(n/2)
= (1 + p + p^2 +...+ p^(n/2-1)) * (1+p^(n/2+1)) + p^(n/2);
可以递归求解
#include<cstdio> #include<iostream> #include<algorithm> #define R register int #define ll long long const int mod=9901; using namespace std; int a,b,tot,ans=1; int pm[50010],cnt[50010]; inline ll q_pow(ll a,ll p) { if(a==0) return 1; R ret=1; a%=mod; for(;p;p>>=1,(a*=a)%=mod) if(p&1) (ret*=a)%=mod; return ret; } ll sum(ll a,ll c) { if(c==0) return 1; if(c&1) return ((1+q_pow(a,(c>>1)+1))%mod*sum(a,(c>>1))%mod)%mod; return ((1+q_pow(a,(c>>1)+1))%mod*sum(a,(c-1)>>1)+q_pow(a,c>>1)%mod)%mod; } int main() { scanf("%d%d",&a,&b); for(R i=2;i*i<=a;i+=(i&1?2:1)) if(a%i==0) { pm[++tot]=i; while(a%i==0) cnt[tot]++,a/=i; } if(a!=1) pm[++tot]=a,cnt[tot]++;//要判断一下A本身是不是素数 for(R i=1;i<=tot;i++) ans=(ans*(sum(pm[i],cnt[i]*b)%mod))%mod; printf("%d\n",ans); }
如有错误,恳请您指正(我太菜了);如有不理解,可留言,我会尽量回复。。。(高中生(逃)。。)
by Jackpei 2019.2.25