素数相关习题
判断素数
素数定义:质数又称素数。一个大于1的自然数,除了1和它自身外,不能被其他自然数整除的数叫做质数;否则称为合数(规定1既不是质数也不是合数)
判断一个数n是不是素数,最简单的方法就是直接遍历,看看从2到n-1是否能够整除n。如下:
bool isPrime(int n){
if(1==n) return false;
for(int i=2;i<n;i++){
if(n%i==0)
return false;
}
return true;
}
因为如果能找到两个因子相乘等于n的话,那么这两个数一定是位于sqrt(n)的两边的,所以我们只用判断[2,sqrt(n)]之间是否有数能够整除n即可,
bool isPrime(int n){
if(1==n) return false;
for(int i=2;i<=sqrt(n);i++){
if(n%i==0)
return false;
}
return true;
}
找出1~n内所有的素数
利用排除法,找到一个素数,那么该素数的倍数就应该都被排除。
#include<bits/stdc++.h>
using namespace std;
bool isPrime(int n){
if(1==n) return false;
for(int i=2;i<=sqrt(n);i++){
if(n%i==0)
return false;
}
return true;
}
vector<int> findPrime(int n){
if(n<=1) return {};
vector<int> temp(n+1);
for(int i=2;i<=n;i++){
//如果i是素数,那i的倍数就得排除
if(isPrime(i)){
for(int j=i*i;j<=n;j+=i)
temp[j]=-1;
}else
{
temp[i]=-1;
}
}
vector<int> res;
for(int i=2;i<n+1;i++){
if(temp[i]!=-1)
res.push_back(i);
}
return res;
}
int main(){
int n;
while(cin>>n){
vector<int> res=findPrime(n);
for(auto& i: res)
cout<<i<<" ";
cout<<endl;
}
system("pause");
return 0;
}
素数相关的面试题
来自 猜数游戏
牛牛和羊羊在玩一个有趣的猜数游戏。在这个游戏中,牛牛玩家选择一个正整数,羊羊根据已给的提示猜这个数字。第i个提示是"Y"或者"N",表示牛牛选择的数是否是i的倍数。
例如,如果提示是"YYNYY",它表示这个数使1,2,4,5的倍数,但不是3的倍数。
注意到一些提示会出现错误。
例如: 提示"NYYY"是错误的,因为所有的整数都是1的倍数,所以起始元素肯定不会是"N"。此外,例如"YNNY"的提示也是错误的,因为结果不可能是4的倍数但不是2的倍数。
现在给出一个整数n,表示已给的提示的长度。请计算出长度为n的合法的提示的个数。
例如 n = 5:
合法的提示有:
YNNNN YNNNY YNYNN YNYNY YYNNN YYNNY
YYNYN YYNYY YYYNN YYYNY YYYYN YYYYY
所以输出12
输入描述:
输入包括一个整数n(1 ≤ n ≤ 10^6),表示已给提示的长度。
输出描述:
输出一个整数,表示合法的提示个数。因为答案可能会很大,所以输出对于1000000007的模
示例1
输入
5
输出
12
思路: 设dp[i]表示输入长度为i时的合法的提示个数,那么根据i的分类可能存在下面几种情况:
-
i为素数,由于素数和前面的所有数都没有依赖关系,即第i位可以为Y或者N,所以dp[i]=dp[i-1]*2;
-
i不是素数的幂次,也就是像6这样的数字,你会发现,它已经被第2位和第3位唯一确定了。例如23分别是YY,那么6一定是Y;23分别是YN或NY或NN,6一定是N,所以说这时候有dp[i]=dp[i-1]
-
i是素数的幂次,它不能唯一确定。例如4,当2为Y时,4不确定,可以是Y,也可以是N。将4和2放入集合 { 2 , 2 2 } {2,2^2} {2,22},所以有NN,YN,YY三种情况(3=2+1)。那么引申一下,加入8就是3个元素的集合 { 2 , 2 2 , 2 3 } {2,2^2,2^3} {2,22,23},共4种情况(4=3+1); 将3和9放入集合 { 3 , 3 2 } {3,3^2} {3,32},有NN,YN,YY三种情况(3=2+1),以此类推。最后将这些情况相乘即可,因为这些集合之间相互不影响
因此,从上面分析中可以看出,长度为n的各位可以分为两类:
- 位数为素数或素数的幂次:这些位上的可能性取决于素数的幂次且小于n的那些数。
- 位数不是素数且不是素数的幂次:当素数位的字符确定了,这些位上的字符也都确定,即都只有一种可能性;
所以, 合法提示组合数问题转化为求所有小于等于n的素数及他们的幂次数的组合数的乘积。也就是把每一个素数和它的幂次归为一类,求出每一类的合法提示组合数,由于类与类之间没有重叠关系,因此总的组合数为所有类的组合数的乘积
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
while(cin>>n){
long long res=1;
vector<bool> visited(n+1,false);
for( int i=2;i<=n;i++){
if(visited[i]) continue;
//排除素数的倍数
//这里改成for(int j=i*i;j<=n;j+=i)也是可以的
for(int j=2*i;j<=n;j+=i){
visited[j]=true;
}
//在n的范围内,该素数的幂次最多为多大
long long temp=i;
int count=0;
while(temp<=n){
temp*=i;
count++;
}
//计算所有素数幂次集合的乘积
res=res*(count+1)%1000000007;
}
cout<<res<<endl;
}
return 0;
}