1001 Yes, Primer Minister
题目链接:yes,prime minister
题目大意:你是《是!首相》里的的唐纳德,你要满足汉弗莱和哈克先生的要求,对于编号从负无穷到正无穷的公务员编号序列进行处理,你要注意哈克先生要求留下最少的公务员以及留下来的公务员编号序列之和是一个质数;而汉弗莱的要求是自己的编号ID必须在留下来的序列之中。现在里来执行这个命令,来选择 [ l , r ] [l,r] [l,r]并且输出最最少保留下来的人数,如果不能就输出 − 1 -1 −1。
题目思路:我们先提取出其中重要的几点,首先就是一段连续而递增的区间,只要我们获得左右端点值,即可知道区间和: ∑ i = l r a i = ( r + l ) ( r − l + 1 ) 2 \sum_{i=l}^r a_i = \frac{(r+l)(r-l+1)}{2} ∑i=lrai=2(r+l)(r−l+1)(不论左右是否为负都成立),我们知道质数的因子就只能是 1 1 1和他自己,那么对于这个区间和 ∑ i = l r a i \sum_{i=l}^r a_i ∑i=lrai的两个因子 ( r + l ) 2 \frac{(r+l)}{2} 2(r+l)和 ( r − l + 1 ) 2 \frac{(r-l+1)}{2} 2(r−l+1),通俗来说其中一个必须是 1 1 1,也就是当 l > 0 , r − l + 1 > 0 l > 0,r-l+1 > 0 l>0,r−l+1>0的时候如果 ∑ i = l r a i \sum_{i=l}^r a_i ∑i=lrai是质数,那么他的区间和一定不超过 2 2 2,而其他 x x x的时候,也有类似的原理;其次就是对于 x x x的分类,对于 x ≥ 0 x \geq 0 x≥0的时候,我们可以思考一下 [ x , x ] 、 [ x − 1 , x ] 、 [ x , x + 1 ] [x,x]、[x-1,x]、[x,x+1] [x,x]、[x−1,x]、[x,x+1]这三个特殊情况是 x < 0 x < 0 x<0所不具有的,然后就是需要把 l l l放到 0 0 0左边的情况,有两种情况:一是找到最小的 y ( y ≥ x ) y(y\geq x) y(y≥x)满足 y y y是质数,那么区间就是 [ − y + 1 , y ] [-y+1,y] [−y+1,y],二是找到最小的 z ( z ≥ x ) z(z\geq x) z(z≥x)满足 2 ∗ y − 1 2*y-1 2∗y−1是质数,那么区间就是 [ − y + 2 , y ] [-y+2,y] [−y+2,y]。
吐槽:比赛的时候我开的另一道,看1001过得多,就来写1001,。第一次是想到了 [ x , x ] 、 [ x − 1 , x ] 、 [ x , x + 1 ] [x,x]、[x-1,x]、[x,x+1] [x,x]、[x−1,x]、[x,x+1]这三个情况,但是当 x x x为负数,我直接去正数轴找,显然出错了。然后看完题解觉得很好写,写完线性筛找出所有质数之后怎么写都没写对,我一看人家STD,没装的质数,直接装除开质数以外的数,只需要二分找一下,然后验证就可以比较答案了,唯一麻烦就是在线性筛加入质数的时候进行一次处理一次即可。
贴一下代码:
#include <iostream>
#include <algorithm>
#include <vector>
#define MAXN 20000010
using namespace std;
int t, x, ans = 0x3f3f3f3f;
bool vis[MAXN];
vector<int> a1;
vector<int> a2;
void get()
{
vis[0] = vis[1] = 1;
for(int i = 2; i < MAXN; i++)
{
if (vis[i] == 1) continue;
if (i % 2 == 1) a2.push_back(i/2+1);
//这个地方处理一下,可以和思路多理解下
a1.push_back(i);
for(int j = 2 * i; j < MAXN; j += i)
vis[j] = 1;
}
}
// ==== ==== ==== ====筛一下
void solve()
{
cin >> x;
if (x >= 0 && vis[x] == 0)
{
cout << 1 << endl;
return ;
}
if (x >=1 && (vis[(x<<1)+1]==0 || vis[(x<<1)-1]==0))
{
cout << 2 << endl;
return ;
}
ans = 0x3f3f3f3f;
int y;
if (x >= 0)
{
y = *lower_bound(a1.begin(), a1.end(), x);
//还可以写 y = lower_bound(a1.begin(), a1.end(), x) - a1;
ans = min(ans, 2*y);
y = *lower_bound(a2.begin(), a2.end(), x);
ans = min(ans, 2*y - 1);
}
else
{
y = *lower_bound(a1.begin(), a1.end(), -x+1);
ans = min(ans, 2*y);
y = *lower_bound(a2.begin(), a2.end(), -x+2);
ans = min(ans, 2*y - 1);
}
cout << ans << endl;
}
int main ()
{
get();
cin >> t;
while(t--)
{
solve();
}
return 0;
}