本次小结要介绍所有有关素数的*知识,题解与模板!
这是目前为止写的最用心的一次博客了,耗时3个小时!边学边做题边写。
首先要介绍的是最普通的素数判定!!!!!
先上例题:
试题 算法提高 素数判断
资源限制
时间限制:1.0s 内存限制:512.0MB
编写一函数IsPrime,判断某个大于2的正整数是否为素数。
样例输入:
5
样例输出:
yes
样例输入:
9
样例输出:
no
注意:是素数输出yes,不是素数输出no,其中yes和no均为小写。
核心思路
:素数的概念!即只可被1和自身整除!!!
Ps. 0,1不是素数哦
AC代码:
#include<iostream>
using namespace std;
int isprime(int n)
{
if (n < 2)
return 0;
int i;
for (i = 2; i < n; i++)
{
if (n%i == 0)
return 0;
else
return 1;
}
}
int main()
{
int n,k;
cin >> n;
k=isprime(n);
if (k == 1)
cout << "yes" << endl;
else
cout << "no" << endl;
return 0;
}
该算法运算步骤较多,而且运算较大数字时会超时。
所以接下来要介绍第一种素数筛选方法:
埃筛(Eratosthenes)
用埃筛进行素数筛选可以有效的提升运算速度,核心思路是:寻找第一个素数,之后将此素数所有的整数倍数全部剔除在运算超大数时,运算步骤大大减少。
以下程序是求一千万以内素数的个数的代码:
#include<iostream>
using namespace std;
#define M 10000000
bool flag[M + 1] = {};//初始化,0为质数
int prime[M];//用来存质数
int main()
{
long long cnt = 0,sum=0;
for (int i=2;i<M+1;i++)
if (flag[i]==0)
{
prime[cnt] = i;
cnt++;
for (int j = 2; j <= M / i; j++)
flag[i*j] = 1;
}
cout << cnt<<endl;
return 0;
}
不过此筛法还不是最优筛法,因为每次扫过公倍数的时候就会重复一次,入剔除2的倍数6,在剔除3的倍数时,还会再扫一遍
来道例题:
试题 算法提高 素数求和
资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
输入一个自然数n,求小于等于n的素数之和
样例输入
2
样例输出
2
数据规模和约定
测试样例保证 2 <= n <= 2,000,000
本题需要注意它的数据规模,比较大,用最普通的素数判定算法,绝对会超时!(只过了两组,当然可能是因为我比较笨)因此我们可以用埃筛来进行和的运算。
AC代码如下:
#include<iostream>
#include<cstring>
using namespace std;
#define M 2000000
bool flag[M + 1] = {};
typedef long long ll;
int main()
{
ll n, sum=0,i;
cin >> n;
for (i = 2; i <= n; i++)
{
if (flag[i]==0)
{
sum += i;
for (int j = 2; j <= n/i; j++)
flag[i*j] = 1;
}
}
cout << sum << endl;
return 0;
}
接下来是第二种素数筛法,也就是大名鼎鼎的:
欧拉筛(线性筛)
这是目前为止我了解到的最棒的筛法了,它的时间复杂度仅有O(n).
欧筛就是一个数只用自己最小的质因数筛去
举个例子:筛掉6的时候只需要用到2,而不用3筛,这样就减少了筛选的步骤
实现代码如下:
void euler_sieve(int n)
{
totPrimes = 0;
memset(flag, 0, sizeof(flag));//记得加头文件
for (int i = 2; i <= n; i++) {
if (!flag[i])
primes[totPrimes++] = i;
for (int j = 0; i * primes[j] <= n; j++) {
flag[i*primes[j]] = true;
if (i % primes[j] == 0)
break;
}
}
}
之后呢,我找到了几道需要用到质数知识的题目,类似于分解质因数,求完数等,题目即题解如下:
试题 算法提高 8-1因式分解
资源限制
时间限制:10.0s 内存限制:256.0MB
问题描述
设计算法,用户输入合数,程序输出若个素数的乘积。例如,输入6,输出23。输入20,输出22*5。
样例
与上面的样例输入对应的输出。
例:
数据规模和约定
输入数据中每一个数在int表示范围内。
AC代码:
#include<iostream>
using namespace std;
int main()
{
int i, n;
cin >> n;
for (i = 2; i <= n; i++)
{
while (n % i == 0)
{
if (i != n)
cout << i << "*";
else
cout << i;
n /= i;
}
}
return 0;
}
试题 算法训练 完数
资源限制
时间限制:1.0s 内存限制:512.0MB
问题描述
一个数如果恰好等于它的因子之和,这个数就称为“完数”。例如,6的因子为1、2、3,而6=1+2+3,因此6就是“完数”。又如,28的因子为1、2、4、7、14,而28=1+2+4+7+14,因此28也是“完数”。编写一个程序,判断用户输入的一个数是否为“完数”。
输入格式:输入只有一行,即一个整数。
输出格式:输出只有一行,如果该数为完数,输出yes,否则输出no。
输入输出样例
样例输入
6
样例输出
yes
AC代码:
#include<iostream>
using namespace std;
int main()
{
int n, i,sum=0;
cin >> n;
for (i = 1; i < n; i++)
if (n%i == 0)
sum += i;
if (sum == n)
cout << "yes" << endl;
else
cout << "no" << endl;
return 0;
}
试题 算法训练 友好数
资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
有两个整数,如果每个整数的约数和(除了它本身以外)等于对方,我们就称这对数是友好的。例如:
9的约数和有:1+3=4
4的约数和有:1+2=3
所以9和4不是友好的。
220的约数和有:1 2 4 5 10 11 20 22 44 55 110=284
284的约数和有:1 2 4 71 142=220
所以220和284是友好的。
编写程序,判断两个数是否是友好数。
输入格式
一行,两个整数,由空格分隔
输出格式
如果是友好数,输出"yes",否则输出"no",注意不包含引号。
样例输入
220 284
样例输出
yes
数据规模和约定
两个整数都小于10000
AC代码:
#include<iostream>
using namespace std;
int main()
{
int a, b,sum1=0,sum2=0;
cin >> a >> b;
int i;
for (i = 1; i < a; i++)
{
if (a%i == 0)
sum1 += i;
}
for (i = 1; i < b; i++)
{
if (b%i == 0)
sum2+= i;
}
if (sum1 == b && sum2 == a)
cout << "yes" << endl;
else
cout << "no" << endl;
return 0;
}