[POJ1845] Sumdiv
数论的公式
这题就是一道数论题。
- 快速幂
一提到A^B,绝对绕不开快速幂。
long long Km(long long a,long long b,long long p)
{
a%=P;
long long ans=1;
while(b)
{
if(b&1) ans=ans*a%p;
a=(a*a)%p;
b>>=1;
}
return ans;
}
原理简介: 将B转化为2进制后发现。只有有1的位置我们才要将答案乘a的k次方。
2.整数分解
A=(k1^n1 k2^n2 ……)其中kn是一个质数且是A的一个约数nn是他的个数。
3.等比数列求和
这个就不太理解了。。 明明有S=(1-q^n)/(1-q)的,但是推了几个不对。。目测是快速幂后再减1时出现的问题。
<后记> 如果直接用公式就会出现失精的情况! 切记。
题解解法:
(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 <bits/stdc++.h>
using namespace std;
const long long P = 9901;
long long Km(long long a,long long b,long long p)
{
a%=P;
long long ans=1;
while(b)
{
if(b&1) ans=ans*a%p;
a=(a*a)%p;
b>>=1;
}
return ans;
}
long long ZC(long long a,long long b) //等比数列求和,递归法;
{
if(b==0) return 1;
long long sum=1;
if(b&1) return ((Km(a,b/2+1,P)+1)*ZC(a,b/2))%9901; //公式;
return ((Km(a,b/2+1,P)+1)*ZC(a,b/2-1)+Km(a,b/2,P))%9901;
}
long long S=1;
int main()
{
long long A,B;
cin>>A>>B;
for(int i=2;i<=sqrt(A);i++)
{
int kn=0;
while(A%i==0)
{
kn++;
A/=i;
}
S=(S*ZC(i,kn*B))%P;
}
if(A>1) S=(S*ZC(A,B)%P)%P;
cout<<S;
}