湖南工学院2022级ACM第二次热身赛--D题--入群条件--题解

原题链接

T285368 入群条件(新生奶茶题)

本题考察的算法为素数筛

基本素数筛(埃氏筛)思想是:

给定一个素数数组,先假定除了0,1两个数之外的所有数全部都是素数

然后从2开始遍历到数组尾部,如果遍历到的数是素数,那么该数的倍数一定不是素数

int[] isprime = new int[1000005];//素数数组


Arrays.fill(isprime,1);//用1填满素数数组,表示全部都是素数
arr[0] = arr[1] = 0;


for(int i = 2; i < 1000005;i++){
    for(int j = 2;i * j < 1000005;j++){

           if(arr[i]==1){//如果i是素数
                arr[i*j] = 0;//i的j倍数一定不为素数
           }

    }    
}

这样我们就得到了一个素数数组,他的用法是arr[i] == 1 时表示i为素数,否则i不是素数

此素数筛预处理的时间复杂度为O(NloglogN)

但是对于本题,会超时

在数据接近1e7的时候,埃氏筛就会很慢,,此时就要用到更加快的筛法--线性筛

顾名思义,线性筛的时间复杂度是线性级,为O(N)

在埃氏筛中,30这个数被筛选了2*15 3*10 5*6三次,越往后,一个数被筛选的次数会越来越多,线性筛就是尽可能的减少被重复运算的次数 

boolean[] arr = new boolean[10000005];
//素数数组
int[] prime = new int[1000005];
//用来存放第i个素数
int sum = 0;
Arrays.fill(arr, true);
arr[0] = false;
arr[1] = false;
//初始化


for (int i = 2; i < arr.length; i++) {
            if (arr[i]) {
                prime[++sum] = i;//是素数存入
            }
    for (int j = 1; j <= sum && i * prime[j] < arr.length; j++) {
                arr[i * prime[j]] = false;//筛选倍数
                if (i % prime[j] == 0) {// 避免重复运算
                    break;
             }
      }
}

如果不是很明白思路,可以自己人工充当一下计算机,运行一下代码

附上本题标程

Java:

import java.io.*;
import java.util.Arrays;
import java.util.StringTokenizer;

public class Main {
    static class input {
        BufferedReader brr = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer stk;

        public String next() throws IOException {
            while (stk == null || !stk.hasMoreTokens()) {
                stk = new StringTokenizer(brr.readLine());
            }
            return stk.nextToken();
        }

        public int nextInt() throws IOException {
            return Integer.parseInt(next());
        }

        public String readLine() throws IOException {
            return brr.readLine();
        }
    }


    public static void main(String[] args) throws IOException {
        input read = new input();
        long ans = 0;
        int n = read.nextInt();
        boolean[] arr = new boolean[10000005];
        int[] prime = new int[1000005];
        int sum = 0;
        Arrays.fill(arr, true);
        arr[0] = false;
        arr[1] = false;
        for (int i = 2; i < arr.length; i++) {
            if (arr[i]) {
                prime[++sum] = i;
            }
            for (int j = 1; j <= sum && i * prime[j] < arr.length; j++) {
                arr[i * prime[j]] = false;
                if (i % prime[j] == 0) {
                    break;
                }
            }
        }
        for (int i = 0; i <= n; i++) {
            ans += prime[read.nextInt()];
        }
        System.out.println(ans);
    }


}

c++:

#include <bits/stdc++.h>
using namespace std;
const int N = 1e7;
int prime[N];
int arr[N];
int cnt = 0;
void init() {
	for (int i = 2; i < N; i++) {
		arr[i] = 1;
	}
	arr[1] = arr[0] = 0;
}
void fun() {
	for (int i = 2; i < N; i++) {
		if (arr[i]) prime[++cnt] = i;
		for (int j = 1; j <= cnt && prime[j]*i < N; j++) {
			arr[i * prime[j]] = 0;
			if (i % prime[j] == 0) {
				break;
			}
		}
	}
}
int main() {
	init();
	fun();
	int n,sum = 0;
	cin >> n;
	n++;
	while(n--){
		int i;
		cin >> i;
		sum += prime[i];
	}
	cout << sum;
	return 0;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值