每日一题 2019/4/10

今天写个大区间素数筛

POJ3689

给你一个区间[l, r],1 <= l <= r <= 1e9, r - l < 1e6,求区间内相邻的素数差值最大值和最小值

显然直接筛是不太现实的,注意到区间只有1e6。

思路转换为把[l, r]的合数求出来,剩下的就是素数直接枚举就行了。

如何求出区间中的合数?

首先知道最小的质因子是sqrt(int) = 2 ^ 16,所以先求出小于2 ^ 16的所有素数。则区间[l,u]中的合数,必定可以表示为这些素数的倍数,然后直接在这个区间枚举就行了。

另外就是需要平移一下[l, r],因为开不了1e9的数组嘛。


int prime[maxn], f[maxn];
bool vis[maxn];
int l, r;
int t;

void init(){
	memset(vis, 0, sizeof vis);
	int m = sqrt(1e6);
	rep(i, 2, m){
		if(!vis[i]){
			for(int j = i * i; j < maxn; j += i) vis[j] = 1;
		}
	}
	t = 0;
	rep(i, 2, maxn - 1) if(!vis[i]) prime[t++] = i;
}

int main()
{
	init();
	while(~scanf("%d %d", &l, &r)){
		if(l == 1) l = 2;
		fill(f, f + r - l + 1, 0);
		rep(i, 0, t - 1){
			int a = (l - 1) / prime[i] + 1, b = r / prime[i];
			rep(j, a, b) if(j > 1) f[j*prime[i]-l] = 1;
		}
		int p = -1, Max = -inf, Min = inf, x1, y1, x2, y2;
		rep(i, 0, r - l){
			if(f[i] == 0){
				if(p == -1) { p = i; continue; }
				if(Max < i - p) Max = i - p, x1 = p + l, y1 = i + l;
				if(Min > i - p) Min = i - p, x2 = p + l, y2 = i + l;
				p = i;
			}
		}
		if(Max == -inf) puts("There are no adjacent primes.");
		else printf("%d,%d are closest, %d,%d are most distant.\n", x2, y2, x1, y1);
	}
	return 0;
}

 

你可能感兴趣的:(每日一题)