P1865 A % B Problem

P1865 A % B Problem

题目链接

题意简述

求区间 [l,r] 内质数的个数

解析

前置知识:

质数是指在大于 1 的自然数中,除了 1 和它本身以外不再有其他因子的自然数。

一层循环判断 2n1 的每一个数是否是它的因子

n=a×b,则 a,b 中必有一个小于等于 n,另一个大于等于 n

因此,可以只判断 2n 的数是否为 n 的因子

static boolean isPrime(int n) {
    if (n == 1) return false;
    for (int i = 2, sq = (int) Math.sqrt(n); i <= sq; ++i) {
        if (n % i == 0) return false;
    }
    return true;
}

那如何处理 区间素数个数呢?

常规的思路是对每次询问的区间进行素数判断并求个数

但是对于 n 次询问,每次都判断区间内的素数个数很大程度上会出现重复,所以我们会想到通过空间换时间的方式,将所询问的所有区间内是否是素数这个东西存下来,用到的时候调用就行,于是我们得到了如下代码

import java.util.Scanner;

public class Main {

    static boolean isPrime(int n) {
        if (n == 1) return false;
        for (int i = 2, sq = (int) Math.sqrt(n); i <= sq; ++i) {
            if (n % i == 0) {
                return false;
            }
        }
        return true;
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt(), m = sc.nextInt();
        boolean[] a = new boolean[m + 1];
        for (int i = 1; i <= m; ++i) {
            a[i] = isPrime(i);
        }
        while (n-- != 0) {
            int l = sc.nextInt(), r = sc.nextInt();
            if (1 <= l && l <= r && r <= m) {
                int sum = 0;
                for (int i = l; i <= r; ++i) {
                    if (a[i]) {
                        ++sum;
                    }
                }
                System.out.println(sum);
            } else {
                System.out.println("Crossing the line");
            }
        }
    }
}

但是在求区间内素数时,仍然有大量重复循环,每次都进行了区间的累加

我们考虑改变询问的式子

sum[l,r]=al++ar=(a1++al1)+al++ar(a1++al1)=(a1++al1+al++ar)(a1++al1)

可以看到变成 1r1l1 的差,他们都是和所给左右端点有关的 前缀的和

若定义 S 为数列 a 的前缀的和,即 Sn=i=1nai,则 sum[l,r]=SrSl1

因此,我们可以预处理出 S 这个数列,每次询问时只需通过一个减法求得区间 [l,r] 的和

前缀和的定义如下:

对于一个给定的数列 A,它的前缀和数列 S 中的第 i 项表示从第 1 个元素到第 i 个元素的总和,即 Si=A1+A2++Ai

定义 区间 [l,r] 的和为 sum[l,r],则有如下式子

sum[l,r]={SrSl1l2S1l=1

Code

import java.util.Scanner;

public class Main {

    static boolean isPrime(int n) {
        if (n == 1) return false;
        for (int i = 2, sq = (int) Math.sqrt(n); i <= sq; ++i) {
            if (n % i == 0) return false;
        }
        return true;
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt(), m = sc.nextInt();
        int[] a = new int[m + 1];
        for (int i = 1; i <= m; ++i) {
            if (isPrime(i)) a[i] = 1;
        }
        // 求 素数个数 的前缀和
        for (int i = 1; i <= m; ++i) {
            a[i] += a[i - 1];
        }
        while (n-- != 0) {
            int l = sc.nextInt(), r = sc.nextInt();
            if (1 <= l && l <= r && r <= m) {
                System.out.println(a[r] - a[l - 1]);
            } else {
                System.out.println("Crossing the line");
            }
        }
    }
}
posted @   Cattle_Horse  阅读(43)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示