递归试炼之约数之和
题目描述
题目分析
解决方案
题目描述
输入
数据范围
0≤A,B≤5×10^7
注意:A和B不会同时为00。
输出
输出一个整数,代表Smod9901的值。
输入样例:
2 3
输出样例:
15
题目分析:
这道题目的难点主要在于如何求一个数的约数之和。这边展示一个约数和公式,具体可以了解约数和定理。
有了这个公式,题目也基本上就解决了。先对A进行质因数分解,记下每个质因数及其次数。最后将所有次数乘以B即得到S的质因数分解结果。再者,根据取模运算的性质,有
①( a + b ) mol c = ( a mol c + b mol c ) mol c
②a * b mol c = [ ( a mol c ) * ( b mol c ) ] mol c
因此,为了避免数据的运算结果过大,可以多次使用取模运算。
解决方案:
#include <iostream>
#include <vector>
using namespace std;
vector<int>divisor[2]; //divisor[0]记录质因数,divisor[1]记录对应的次数
void divise(int n){
int i=3,j=n,k;
if(j%2==0){ //先分解2再分解其余奇数,这样可避免判断其他偶数
k=0;
while(j%2==0){
k++;
j/=2;
}
divisor[0].push_back(2);
divisor[1].push_back(k);
}
while(j>=i){ //判断其余奇数
if(j%i==0){
k=0;
divisor[0].push_back(i);
while(j%i==0){
j/=i;
k++;
}
divisor[1].push_back(k);
}
i+=2;
}
}
int remain(int k){
int a=1,b=1;
for(int i=1;i<=divisor[1][k];i++){ //运用取模运算的性质进行计算
b=b*divisor[0][k]%9901; //多次使用取模运算,避免数据越界
a=(a+b)%9901;
}
return a;
}
int main(){
int n,m;
cin>>n>>m;
divise(n);
for(int i=0;i<divisor[0].size();i++)
divisor[1][i]*=m; //得到S质因数的次数
int remainder=remain(0); //用于比较筛选,从第一个因数开始
for(int i=1;i<divisor[0].size();i++) //遍历每一个因数
remainder=remainder*remain(i)%9901; //取模运算避免数据越界
cout<<remainder;
return 0;
}