Yes, Prime Minister
Time Limit: 10000/10000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 583 Accepted Submission(s): 228
https://acm.hdu.edu.cn/showproblem.php?pid=7025
Problem Description
Mr. Hacker's Department of Administrative Affairs (DAA) has infinite civil servants. Every integer is used as an id number by exactly one civil servant. Mr. Hacker is keen on reducing overmanning in civil service, so he will only keep people with consecutive id numbers in [l,r] and dismiss others.
However, permanent secretary Sir Humphrey's id number is x and he cannot be kicked out so there must be l≤x≤r. Mr. Hacker wants to be Prime Minister so he demands that the sum of people's id number ∑ri=li must be a prime number.
You, Bernard, need to make the reduction plan which meets the demands of both bosses. Otherwise, Mr. Hacker or Sir Humphrey will fire you.
Mr. Hacker would be happy to keep as few people as possible. Please calculate the minimum number of people left to meet their requirements.
A prime number p is an integer greater than 1 that has no positive integer divisors other than 1 and p.
Input
The first line contains an integer T(1≤T≤106) - the number of test cases. Then T test cases follow.
The first and only line of each test case contains one integer xi(−107≤xi≤107) - Sir Humphrey's id number.Output
For each test case, you need to output the minimal number of people kept if such a plan exists, output −1 otherwise.
Sample Input
10
-2
-1
0
1
2
3
4
5
6
7
Sample Output
6
4
3
2
1
1
2
1
2
1
标签:素数筛+二分
题意:在包含x的连续的连续区间内找到素数和最小的范围
思路:先用素数筛法将题目范围内的所有素数筛出来,分类:
当x=0的时候,最小分为为0,1,2,ans=3;
当x>0的时候,
如果x本身是素数,则ans=1,
如果x+x+1/x+x-1为素数,则ans=2,
如果还没有答案(这里是没有考虑到的地方,2*x+1/2*x-1不一定是素数,比如说x=11的时候,2*11-1=21=3*7),则向左到x轴负半轴延长到-x,那么此时x-x=0;现在需要找一个质数或者相邻的两个数的和为质数的数,“不妨找到第一个大于x的质数和第一个大于x且2*x+1为质数的数”,这里直接在数据范围内的所有素数中用二分查找找到满足要求的位置即可
当x<0的时候,将范围延长至x,x-x=0,此时与👆🏻第三种的情况一样
补充:upper_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
#include<bits/stdc++.h>
using namespace std;
const int lim=3e7+5;
const int maxn=7e7+5;//maxn要比lim大
int vis[maxn],prime[maxn],prime2[maxn],tot,top;
//素数筛
void find()
{
vis[1]=1;
for (int i=2; i<lim; i++)
{
if (!vis[i]) prime[++tot]=i;
for (int j=1;j<=tot&&i*prime[j]<lim;j++)
{
vis[i*prime[j]]=1;
if (i%prime[j]==0)
break;
}
}
for (int i=1; i<=lim; i++)
{
if (!vis[2*i-1])
prime2[++top]=i;
}//保留2*i-1的素数
return ;
}
int main()
{
find();//筛出范围内所有的素数
int t,x;
scanf("%d",&t);
while (t--)
{
scanf("%d",&x);
if (x==0)
{
printf("3\n");
continue;
}//x=0:0,1,2
if (x>0)
{
if (!vis[x])
{
printf("1\n");
continue;
}//本身是素数
if (!vis[2*x+1]||!vis[x*2-1])
{
printf("2\n");
continue;
}//x+x+1/x+x-1是素数
//如果还没有 往负数区域扩展到-x 这样x+(-x)抵消了 那么再往前找大于x的第一个素数(prime)和第一个大于x且2*x+1为素数的数(prime2)
int ans=0x3f3f3f3f;//无穷大
int pos=upper_bound(prime+1,prime+tot+1,x)-prime;
ans=min(ans,prime[pos]*2);//
pos=upper_bound(prime2+1,prime2+lim+1,x)-prime2;
ans=min(ans,2*prime2[pos]-1);
printf("%d\n",ans);
}
else if (x<0)
{//x<0的时候 就和x/2*x+1/2*x-1都不是质数的情况一样
x=-x;
int ans=0x3f3f3f3f;
int pos=upper_bound(prime+1,prime+tot+1,x)-prime;
ans=min(ans,prime[pos]*2);
pos=upper_bound(prime2+1,prime2+top+1,x+1)-prime2;//
ans=min(ans,2*prime2[pos]-1);
printf("%d\n",ans);
}
}
return 0;
}