算数基本定理
素数
首先要了解素数和合数的区别,一个大于1的正整数,如果只有1和它本身两个约数,就称它为素数,否则,称为合数。
定理内容
如果不考虑排列次序的话,每个大于1的自然数都只能有一种方式分解成若干个(大于等于1个)素数的乘积。
性质
1.(存在性)每个大于1的自然数都可以分解成素数的乘积。
2.(唯一 性)这种分解,再不考虑排 列次序的意义下,是唯一的。
例子
24=3*8=3*4*2=3*2*2*2
24=4*6=2*2*3*2
由上可看出,24最后一定会分解成2*2*2*3这四个素数的乘积。
推论
1.如果素数p整除两个整数a和b的乘积ab,则p必然会整除a或b。
2.两个大于1的数的乘积等于它们最小公倍数和最大公约数的乘积。
推论过程见参考。
题目
2019第十届蓝桥杯B组决赛D题求值
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LskfixuM-1622632878702)(C:\Users\29912\AppData\Roaming\Typora\typora-user-images\image-20210518215539020.png)]
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100005;
int maxn = 0;
int minn = 0x3f3f3f3f;
int dir[4][2] = {1, 0, 0, 1, -1, 0, 0, -1};
int a[N], n, m, T, cnt, ans;
bool vis[N];
vector<int> prime;
void init() {//素数筛
for (int i = 2; i <= 3000; i++) {
if (!vis[i]) {
for (int j = i * i; j <= 30000; j += i) {
vis[j] = true;
}
}
}
for (int i = 2; i <= 2019; i++) {
if (!vis[i]) prime.push_back(i);
}
return;
}
int cal(int x) {//求约数个数
int num[123];
memset(num, 0, sizeof(num));
int k = prime.size(), cnt = 0;
for (int i = 0; i < k; i++) {
if (x % prime[i] == 0) {
cnt++;
while (x % prime[i] == 0) {
x /= prime[i];
num[cnt]++;
}
}
}
int ans = 1;
for (int i = 1; i <= cnt; i++) {
ans *= (num[i] + 1);
}
return ans;
}
void solve() {
init();
for (int i = 1; i <= 100000; i++) {
if (cal(i) == 100) {
cout << i << endl;
break;
}
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
solve();
return 0;
}
答案
45360
2020第十届蓝桥杯B组C题阶乘约数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uuTJbz6x-1622632878704)(C:\Users\29912\AppData\Roaming\Typora\typora-user-images\image-20210429211405034.png)]
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100005;
int maxn = 0;
int minn = 0x3f3f3f3f;
int dir[4][2] = {1, 0, 0, 1, -1, 0, 0, -1};
int a[N];
void solve() {
for (int i = 2; i <= 100; i++) {
int x = i;
for (int j = 2; j * j <= x; j++) {
if (x % j == 0) {
int cnt = 0;
while (x % j == 0) ++cnt, x /= j;
a[j] += cnt;
}
}
if (x != 1) a[x]++;
}
unsigned long long ans = 1;
for (int i = 1; i <= 100; i++) {
if (a[i]) {
// cout << i << " " << a[i] << endl;
ans = ans * (a[i] + 1);
}
}
cout << ans << endl;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
solve();
return 0;
}
答案
39001250856960000
参考
acwing 871.约数之和
基本思想:
如果 N=p1c1∗p2c2∗…∗pkck
约数个数:(c1+1)∗(c2+1)∗…∗(ck+1)(c1+1)∗(c2+1)∗…∗(ck+1)
约数之和: (p10+p11+…+p1c1)∗…∗(pk0+pk1+…+pkck)(p10+p11+…+p1c1)∗…∗(pk0+pk1+…+pkck)
**核心代码:while (b – ) t = (t * a + 1) % mod; **
过程
t=t∗p+1
t=1
t=p+1
t=p2+p+1
……
t=pb+pb-1+…+1
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100005;
int maxn = 0;
int minn = 0x3f3f3f3f;
const int mod = 1e9 + 7;
int dir[4][2] = {1, 0, 0, 1, -1, 0, 0, -1};
int a[N], n, m, k, T, cnt;
ll ans = 1;
void solve() {
unordered_map<int, int> hash;
int x;
cin >> n;
while (n--) {
cin >> x;
for (int i = 2; i <= x / i; ++i) {
while (x % i == 0) {
x /= i;
hash[i]++;
}
}
if (x > 1) hash[x]++;
}
for (auto i : hash) {
ll a = i.first, b = i.second, t = 1;
while (b--) {
t = (t * a + 1) % mod;
}
ans = ans * t % mod;
}
cout << ans << endl;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
solve();
return 0;
}