素数距离问题--以为存储素数表会更快,结果sqrt更快

来源:互联网 发布:超级优化女主 编辑:程序博客网 时间:2024/06/05 02:51

地址:http://acm.nyist.net/JudgeOnline/problem.php?pid=24

素数距离问题

时间限制:3000 ms  |  内存限制:65535 KB
难度:2
描述
现在给出你一些数,要求你写出一个程序,输出这些整数相邻最近的素数,并输出其相距长度。如果左右有等距离长度素数,则输出左侧的值及相应距离。
如果输入的整数本身就是素数,则输出该素数本身,距离输出0
输入
第一行给出测试数据组数N(0<N<=10000)
接下来的N行每行有一个整数M(0<M<1000000),
输出
每行输出两个整数 A B.
其中A表示离相应测试数据最近的素数,B表示其间的距离。
样例输入
36810
样例输出
5 17 111 1

思路:

一开始想到的是用一个素数表来存储,用猜想6N+-1的原则,只需要算到6N+5的时候,就足够判断是中间,左边,还是右边了。用到厄拉多塞筛法,两个for,一步步乘以质数,将非质数排除,最后直接往两边找就可以了。结果全超时了。。

原本想用sqrt,想着重复算sqrt(左,中,右)会比较慢。结果看到讨论区,用这种方法做c的,能ac。我也试着用java,发现也可以。很费解,原以为sqrt慢,结果更快了。

无奈之下,只好演算下,发现3*sqrt(m)[最好情况]总是会小于m+5的,加上讨论区,有人把所以范围内的素数输出来,发现,绝大部分距离在0-2之间。当m=10000时,假设5*sqrt(m)也会小于m+5.总是会存储素数表的快。

这是讨论区的,将c改java

public static void sqrtPrimesMinDistance1(int m) {int tmpR, tmpL, minR, minL;minR = minL = 0;tmpR = tmpL = m;while (true) {if (isPrimes(tmpL)) {System.out.println(m - minL + " " + minL);break;}if (isPrimes(tmpR)) {System.out.println(m + minR + " " + minR);break;}tmpL--;tmpR++;minL++;minR++;}}
原本以为他没有考虑到左距离和右距离的比较久直接跳出了,还以为是测试数据有bug。后面才发现,这里设计得很巧妙。用了两个if,先判左边,如果右边相同就取左边,若小也取左边,也刚好就break。两个符合情况,就判下一个右边的if。结果就很符合题意了。

而我写的

public static void sqrtPrimesMinDistance2(int m) {int tmpR, tmpL, minR, minL;minR = minL = m;tmpR = tmpL = m;if (isPrimes(m)) {System.out.println(m + " 0");return;}while (true) {if (isPrimes(tmpL)) {minL = m - tmpL;}if (isPrimes(tmpR)) {minR = tmpR - m;}if (minR != m || minL != m) {if (minL <= minR)System.out.println(tmpL + " " + minL);elseSystem.out.println(tmpR + " " + minR);break;}}}
先得到值后,再做后面的判断,多此一举,结果还超时了。

最后附上源码:

import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt();while (n-- > 0) {int m = sc.nextInt();// findPrimesMinDistance(m);sqrtPrimesMinDistance1(m);}}public static boolean isPrimes(int m) {// 特殊值判断if (m == 0 || m == 1)return false;if (m == 2)return true;for (int i = 2; i <= Math.sqrt(m); i++) {if (m % i == 0)return false;}return true;}// 仿造讨论区的一模一样,318 923,本以为没有考虑到前后谁到谁小的情况就直接跳出了,后来发现很巧妙设计public static void sqrtPrimesMinDistance1(int m) {int tmpR, tmpL, minR, minL;minR = minL = 0;tmpR = tmpL = m;while (true) {if (isPrimes(tmpL)) {System.out.println(m - minL + " " + minL);break;}if (isPrimes(tmpR)) {System.out.println(m + minR + " " + minR);break;}tmpL--;tmpR++;minL++;minR++;}}// 通过存储范围内的素数表,直接取值,还超时。// 想一想也有可能,用素数表,就要算m+5(除0/1)次,用sqrt,算的是中间+左+右-->3*sqrt(m)次,// 演算了下,发现真的是sqrt计算量更小public static void findPrimesMinDistance(int m) {int[] primes = new int[m + 5];for (int i = 2; i < primes.length; i++) {if (primes[i] == 0)for (int k = 2; k * i < primes.length; k++) {primes[k * i] = 1; // 非质数都为1}}if (primes[m] == 0) // 本身是质数System.out.println(m + " 0");else {int minDistance = 0;int tmpR = m;// 向右找while (++tmpR < primes.length) {if (primes[tmpR] == 0) {minDistance = tmpR - m;break;}}// 向左找int tmpL = m;while (--tmpL > 0) {if (primes[tmpL] == 0) {if (m - tmpL <= minDistance) { // <=都是取到左边的minDistance = m - tmpL;} elsetmpL = tmpR;break;}}System.out.println(tmpL + " " + minDistance);}}}






0 0
原创粉丝点击