题目大意:判断2到m有多少个数字是合法的。
对于给定的n个数,是合法的;其他数字若是合法,那么必须存在2到n-1的约数,且这些约数都是合法的。
暴力求解:从小到大枚举2到m,如果约数都合法,标记该数字合法;如果遇到一个不合法的约数,则不标记合法。
需要从小到大确定是否合法,保证用到的约数都是更小的、已确定是否合法。时间复杂度:
#include <stdio.h>
#include <string.h>
#define N 300005
int t, n, m, i, j, k, ans, f[N];
int main(){
scanf("%d", &t);
while(t--){
scanf("%d%d", &n, &m);
memset(f, ans=0, sizeof(f));
for(i=1; i<=n; i++){
scanf("%d", &k);
f[k] = 1;
}
for(i=2; i<=m; i++){
if(f[i]) ans++;
else{
for(k=0, j=2; j*j<=i; j++){
if(i%j) continue;
k = 1;
if(!f[j] || !f[i/j]) break;
}
if(k && j*j > i) ans++, f[i] = 1;
}//有约数且约数都合法
}
printf("%d\n", ans);
}
return 0;
}筛选法求素数:用筛法预处理出每个数字的约数个数(被筛掉次数),保存到数组c,如c[i]表示i的约数个数(2到n-1),如果是质数,约数设为无穷大。
题目要求,所有约数都是合法的;那我们就用合法的数字对2到m的数字进行筛选法求素数;如果“约数”个数恰好根c一致,那么全部约数都是合法的。(质数永不合法,除非属于集合S)。
时间复杂度:
#include <stdio.h>
#include <string.h>
#define N 300005
int t, n, m, i, j, k, ans, c[N], f[N];
int main(){
for(i=2; i<N; i++){
if(c[i] == 0) c[i] = N;//质数无真因子
for(j=i+i; j<N; j+=i) c[j]++;
}//统计约数个数
scanf("%d", &t);
while(t--){
scanf("%d%d", &n, &m);
memcpy(f, c, sizeof(f));
for(i=1; i<=n; i++){
scanf("%d", &k);
ans = f[k] = 0;//约数被筛完合法
}
for(i=2; i<=m; i++){
if(f[i] > 0) continue;//不合法
ans++;
for(j=i+i; j<=m; j+=i) f[j]--;
}//合法的数能被合法的数筛完
printf("%d\n", ans);
}
return 0;
}


京公网安备 11010502036488号