题目一 试除法求约数
题解思路
- 用 i 遍历1到sqrt(n);
- 将其中能整除的数放入结果中,同时把 n / i 也放入结果集(约数总是成对出现);
- 特判:如果n / i == i ,只放一个进去;
代码实现
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
void divi(int n)
{
int sq = sqrt(n);
vector<int>q;
for(int i = 1;i <= sq;i ++ )
{
if(n % i == 0)
{
q.push_back(i);
if(n / i == i)
{
continue;
}
q.push_back(n / i);
}
}
sort(q.begin(), q.end());
for(auto a : q)
{
cout << a << ' ';
}
cout << endl;
}
int main()
{
int n, a;
cin >> n;
while(n -- )
{
scanf("%d", &a);
divi(a);
}
return 0;
}
题目二 求约数个数
解题思路
数学公式:
一个数N 可以写成:N = (p1x1)(p2x2)(p3x3)…(pkxk),其中pi为质数,xi为正整数。则N的约数个数为:(x1+1)(x2+1)(x3+1)…(xk+1)
例如:12 可以分解为:22 * 31 ,则其约数个数 = (2 + 1)(1 + 1) = 6个
- 分解质因数;
- 带入求约数个数的公式;
代码实现
#include<iostream>
#include<algorithm>
#include<unordered_map>
#include<cmath>
using namespace std;
unordered_map<int, int> map;
long long res = 1;
const int N = 1e9 + 7;
int main()
{
int n, x, sq;
cin >> n;
while(n -- )
{
scanf("%d", &x);
sq = sqrt(x);
for(int i = 2;i <= sq;i ++ )
{
while(x % i == 0)
{
map[i] ++ ;
x /= i;
}
}
if(x > 1)
{
map[x] ++ ;
}
}
for(auto i : map)
{
res = res * (i.second + 1) % N;//在累乘过程中就取模,防止超出long long 大小限制;
}
cout << res;
return 0;
}
题目二 求约数之和
题解思路
数学公式:
正整数n可以写成:n = p1e1 p2e2 p3e3 … pkek ;
则其余数之和等于:(1 + p1 + p12 + p13 + … + p1e1)(1 + p2 + p22 + p23 + … + p2e2)…(1 + pk + pk2 + pk3 + … + pkek);
- 分解质因数;
- 带入公式求解;
代码实现
#include<iostream>
#include<algorithm>
#include<cmath>
#include<unordered_map>
using namespace std;
const int N = 1e9 + 7;
unordered_map<int ,int> map;//质因子为key,幂次为value
typedef long long LL;
int main()
{
int n, m, sq;
cin >> n;
while (n -- )
{
scanf("%d", &m);
sq = sqrt(m);
for (int i = 2;i <= sq;i ++ )
{
while (m % i == 0)
{
map[i] ++ ;
m /= i;
}
}
if (m > 1)
{
map[m] ++ ;
}
}
LL res = 1;
for (auto i : map)
{
LL a = i.first;
LL b = i.second;
LL t = 1;
//实现(1 + pk + pk^2^ + pk^3^ + ... + pk^ek^)的步骤
while (b -- )
{
t = (t * a + 1) % N;
}
//累乘求结果
res = res * t % N;
}
cout << res;
return 0;
}
算法具体解析
原链接:https://www.acwing.com/solution/content/248459/
题三 求最大公约数
解题思路
辗转相除法:
(a, b) = (a % b, b) = (b, a %b)
相当于每一步都把数字进行缩小,等式右边就是每一步对应的缩小结果。
对(a, b)连续使用辗转相除,直到小括号内右边数字为0,小括号内左边的数就是两数最大公约数
代码实现
#include<iostream>
#include<algorithm>
using namespace std;
void gcb(int a, int b)
{
if(b == 0)
{
cout << a << endl;
return ;
}
else
{
gcb(b, a % b);
}
}
int main()
{
int n, a, b;
cin >> n;
while(n -- )
{
scanf("%d%d", &a, &b);
gcb(a, b);
}
return 0;
}