poj2689
题意:求区间[l,u]内,距离最近的两个素数,和距离最远的两个素数。区间长度最大1000000,l和u都在int范围内。
分析:由于l,u在2^31内,所以先从1到2^16筛素数。这些素数足以用来判断2^31内的所有数字是否为素数,对于每对l,u,用已知的1~2^16内的素数圈定一个可以筛l,u之间的数字的范围,来筛l,u之间的数字。
View Code
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> using namespace std; #define maxn 1 << 17 #define maxl 1000005 int l, u; bool is[maxn]; long long prm[maxn]; int n; bool ans[maxl]; int prime[maxl]; int num; int getprm(int n) { int i, j, k = 0; int s, e = (int) (sqrt(0.0 + n) + 1); memset(is, 1, sizeof(is)); prm[k++] = 2; is[0] = is[1] = 0; for (i = 3; i < e; i += 2) if (is[i]) { prm[k++] = i; for (s = i * 2, j = i * i; j < n; j += s) is[j] = 0; } for (; i < n; i += 2) if (is[i]) prm[k++] = i; return k; } void work() { for (int i = 0; i < u - l + 1; i++) ans[i] = true; if (l == 1) ans[0] = false; num = 0; for (int i = 0; i < n && prm[i] * prm[i] <= u; i++) { long long temp = (l + prm[i] - 1) / prm[i] * prm[i]; if (temp == prm[i]) temp += prm[i]; while (temp <= u) { ans[temp - l] = false; temp += prm[i]; } } for (int i = 0; i < u - l + 1; i++) if (ans[i]) prime[num++] = l + i; if (num < 2) { printf("There are no adjacent primes.\n"); return; } int ans1 = 0, ans2 = 0; for (int i = 0; i < num - 1; i++) { if (prime[ans1 + 1] - prime[ans1] > prime[i + 1] - prime[i]) ans1 = i; if (prime[ans2 + 1] - prime[ans2] < prime[i + 1] - prime[i]) ans2 = i; } printf("%d,%d are closest, %d,%d are most distant.\n", prime[ans1], prime[ans1 + 1], prime[ans2], prime[ans2 + 1]); } int main() { //freopen("t.txt", "r", stdin); n = getprm(1 << 16); while (~scanf("%d%d", &l, &u)) { work(); } return 0; }