前言:
最近这几篇论文,我个人感觉知识点太散了,所以,从今以后,我们将系统地学习编程
课题:唯一性定理
引入:
定理很简单:任何一个大于1的自然数 ,都可以唯一分解成有限个质数的乘积。
公式也只有两个:
公式一(算约数个数):个数等于=(1+n1)(1+n2)(1+n3)... (1+nn)
注:n是每个因数的次数
公式二(算约数之和):
(对不起,打字我实在打不出)
OK,就这些,接下来,就是实操了。
例题精讲:
1. 4900 - 数论:唯一性定理 约数个数
给定 n 个正整数 ai,请你输出这些数的乘积的约数个数,答案对 10^9+7 取模
输入
第一行包含整数 n。 接下来 n 行,每行包含一个整数 ai。
输出
输出一个整数,表示所给正整数的乘积的约数个数,答案需对 10^9+7 取模。
样例
输入
3
2
6
8
输出
12
提示
1≤n≤100, 1≤ai≤2×10^9
分析:
非常简单,直接套公式,OK直接上代码:
#include<bits/stdc++.h>
#define long long int
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC target("avx")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
using namespace std;
signed main(){
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
map<int,int> sum;
int n=1,m,k=0,l=1,h;
cin>>m;
while(m--){
cin>>h;
n*=h;
}
for(int i=2;n>1;++i){
while(n%i==0){
n/=i;
sum[i]++;
}
}
auto it = sum.begin();
for(;it!=sum.end();it++){
m=it->second;
m++;
l*=m;
}
cout<<l<<endl;
return 0;
}
(为了防止超时,我加了一些预处理)
提交下,一遍过。
2. 4901 - 数论: 唯一性定理 求约数之和
给定 n 个正整数 ai,请你输出这些数的乘积的约数之和,答案对10^9+7 取模
输入
第一行包含整数 n。 接下来 n 行,每行包含一个整数 ai。
输出
输出一个整数,表示所给正整数的乘积的约数之和,答案需对 109+7 取模
样例
输入
3
2
6
8
输出
252
提示
1≤n≤100, 1≤ai≤2×10^9
分析:
这道题同上一道,只要套公式,OK不说了上代码:
#include <bits/stdc++.h>
using namespace std;
const long mod = 1e9 + 7;
int main() {
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
long long n;
cin >> n;
map<int, int> primes;
while (n--) {
int x;
cin >> x;
for (int i = 2; x>1; i++)
while (x % i == 0) {
x /= i;
primes[i] ++;
}
if (x > 1) primes[x] ++;
}
long long res = 1;
for (auto p : primes) {
long long a = p.first, b = p.second;
long long t = 1;
while (b--) t = (t * a + 1) % mod;
res = res * t % mod;
}
cout << res << endl;
return 0;
}
提交一下,AC了。
好,下一题。
3. 4952 - 数论:唯一性定理 发奖金
有n元,平均分给k个人,每个人拿到的是素数金额的奖金,当然人越少拿到的奖金也越多,请问给定奖金总额的情况下没,至少需要多少人才能让每人拿到最大的素数金额的奖金。有多个测试数据
输入
第一行,一个整数,表示有T组测试数据 第二行到第T+1行,每行1个整数,表示奖金数
输出
输出T行,每行1个整数,表示最少需要的人数,如果没有则输出0
样例
输入
3
3
4
100
输出
1
2
20
提示
50%的测试点输入数据保证 1≤T≤5,1≤N≤10000
70%的测试点输入数据保证 1≤T≤10,1≤N≤1000000000
100%的测试点输入数据保证 1≤T≤10,1≤N≤2000000000
分析:
这道题看起来数据规模大,但照常做即可(唯一一点,要防止“奖金”没除干净,要比大小),OK上代码。
#include<bits/stdc++.h>
using namespace std;
signed main() {
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
long long m,n,l,ans;
cin>>m;
while(m--) {
cin>>n;
l=n;
ans=n;
for(int i=2; i*i<=n; ++i) {
while(l%i==0) {
l/=i;
ans=i;
}
}
cout<<n/max(l,ans)<<endl;
}
return 0;
}
一遍过。
课后练习:
4. 4951 - 数论:唯一性定理 超级完全数
真因子之和等于它本身的数称为完数(或称完全数),例如28的真因子有:1,2,4,7,14并且1+2+4+7+14=28,所以28是完数。 乐乐得到了一些数字n,这些数有的比较大(1<=n<=1e9),他想知道这些数是不是完数
输入
一个正整数N (1<=n<=1e9)
输出
如果是完数,输出Y,否则输出N
样例
输入
28
输出
Y
总结:
今天我们讲了数论唯一性定理比较基础的部分,但下节课我们的内容会难一点,这要大家自己钻研。
大家都懂了吗?
附录:
题目网址:
问题来源: