赞
踩
地址:http://acm.nyist.net/JudgeOnline/problem.php?pid=24
3
6
8
10
5 1
7 1
11 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);
- else
- System.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;
- } else
- tmpL = tmpR;
- break;
- }
- }
- System.out.println(tmpL + " " + minDistance);
- }
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。