终于放假了啊啊啊。
今天上课做的一道数学题,第二问用列举好麻烦,做的时候想写一个程序求,可能我太闲了吧()
关于“衍生质数”
已知k为合数,且1<k<100,当k的各数位上的数字之和为质数时,称此质数为k的“衍生质数”.
(1)若k的“衍生质数”为2,则k=_____;
(2)设集合 A={P(k)|P(k)为k的“衍生质数”},B={k|P(k)为k的“衍生质数”},则集合A∪B中元素的个数是_____
.——《步步高练透》数学人教B版必修1 培优课与集合有关的创新问题T10
程序求解
其实就是模拟嘛,求出A集合中的质数,再对应找B集合中元素。由于质数与合数不可能存在交集,即A与B不存在交集,因此最后的结果就是两个集合的元素个数之和了。
因为是自己实现,时间复杂度这种东西也不需要考虑,但是这里还是用质数筛法之一 ——欧拉筛来实现。
-
欧拉筛
欧拉筛又名线性筛,可以在O(n)的时间复杂度内筛出质数。
在说这个之前,先了解一下埃氏筛(埃拉托斯特尼筛法)。其实很简单,如果一个数是质数,那么这个数的倍数必然是合数;反过来说,合数被质因数分解就印证了这一点。所以它的过程就是如果我们从小到大考虑每个数,然后同时把当前这个数的所有(比自己大的)倍数记为合数,那么运行结束的时候没有被标记的数就是质数了。(我记得九下数学课本上有这个的相关介绍,但是不考,所以不讲很难发现。)
考虑还能再优化吗?例如12这个数,它的质因数(既是质数又是它的因数)有2,3这两个数,所以在这个过程中会被筛两遍,可我们只需要筛一遍就够了,这就会造成重复被筛的现象,这里只是拿12举例,如果是更大的数,重复被筛的次数就增多了,所以这种做法显然不太高效。因此欧拉筛就登场了。
它的核心思想是:让每一个合数被其最小质因数筛到。
具体过程就是:从2~n,如果一个数x没被划掉,那么把它放进维护的质数表里,然后用x去划掉x * 质数表内元素(必然为合数);如果x没被划掉,不把它放进质数表,划掉 x * 质数表内元素(直到表内元素是它的倍数)。
这么说有点抽象,例如:
2没有被划掉,加入质数表,再用2去乘质数表内的每个数再划掉(2×2=4,划掉4)
3没有被划掉,加入质数表,再用3去乘质数表内的每个数再划掉(2×3=6,划掉6;3×3=9,划掉9)
下一个数是4,即使被划掉了也要遍历,只是意味着不是质数不需要加入质数表。
用4去乘质数表内的数再划掉(2×4=8,划掉8),此时4是2的倍数,我们应该让每一个合数被最小质因数筛到,此时应该让2筛而不是4,所以我们不再用4去筛后面的数。
......
后面的以此类推,最后没有被划掉的就是质数。
以上为关于欧拉筛的简要介绍。
模板可以参考:筛法 - OI Wiki (oi-wiki.org)
-
相关说明
这道数学题的范围在1~100,考虑到求解其他数据,设置了一个可输入的区间范围变量。
代码丑陋,勿喷()。
-
Code
#include<bits/stdc++.h> using namespace std; const int MAXN=1e6; int l,r; vector<int> A,B; int s_A,s_B; bool not_prime[MAXN]; void euler(int n,int s) { for(int i=2;i<=n;i++) { if(!not_prime[i]&&i<=s) { A.push_back(i); s_A++; } for(int p:A) { if(p*i>n) break; not_prime[p*i]=1; if(i%p==0) break; } } return; } void solve() { for(int i=l;i<=r;i++) { if(i==1||!not_prime[i]) continue; int x=i,s=0; while(x) s+=x%10,x/=10; if(find(A.begin(),A.end(),s)!=A.end()) { B.push_back(i); s_B++; } } return; } void print() { printf("\n"); printf("A={ "); for(int p:A) printf("%d ",p); printf("} %d个元素\n",s_A); printf("\n"); printf("B={ "); for(int p:B) printf("%d ",p); printf("} %d个元素\n",s_B); printf("\n"); printf("A∪ B共%d个元素\n",s_A+s_B); return; } int main() { printf("输入k的范围(l,r):"); scanf("%d %d",&l,&r); l--,r--; int x=r,s=0; while(x) s+=x%10,x/=10; euler(r,s); solve(); print(); return 0; }