数论:唯一性定理(上)

前言:

最近这几篇论文,我个人感觉知识点太散了,所以,从今以后,我们将系统地学习编程

课题:唯一性定理

引入:

定理很简单:任何一个大于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

总结:

今天我们讲了数论唯一性定理比较基础的部分,但下节课我们的内容会难一点,这要大家自己钻研。

大家都懂了吗?

附录:

题目网址:

4900 - 数论:唯一性定理 约数个数

4901 - 数论: 唯一性定理 求约数之和

4952 - 数论:唯一性定理 发奖金

4951 - 数论:唯一性定理 超级完全数

问题来源:

江南OJ在线判题系统

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值