2021“MINIEYE杯”中国大学生算法设计超级联赛(6)(补题)

1001 Yes, Primer Minister

题目链接:yes,prime minister

题目大意:你是《是!首相》里的的唐纳德,你要满足汉弗莱和哈克先生的要求,对于编号从负无穷到正无穷的公务员编号序列进行处理,你要注意哈克先生要求留下最少的公务员以及留下来的公务员编号序列之和是一个质数;而汉弗莱的要求是自己的编号ID必须在留下来的序列之中。现在里来执行这个命令,来选择 [ l , r ] [l,r] [lr]并且输出最最少保留下来的人数,如果不能就输出 − 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)(rl+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(rl+1),通俗来说其中一个必须是 1 1 1,也就是当 l > 0 , r − l + 1 > 0 l > 0,r-l+1 > 0 l>0,rl+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 x0的时候,我们可以思考一下 [ x , x ] 、 [ x − 1 , x ] 、 [ x , x + 1 ] [x,x]、[x-1,x]、[x,x+1] [x,x][x1,x][x,x+1]这三个特殊情况是 x < 0 x < 0 x<0所不具有的,然后就是需要把 l l l放到 0 0 0左边的情况,有两种情况:一是找到最小的 y ( y ≥ x ) y(y\geq x) y(yx)满足 y y y是质数,那么区间就是 [ − y + 1 , y ] [-y+1,y] [y+1,y],二是找到最小的 z ( z ≥ x ) z(z\geq x) z(zx)满足 2 ∗ y − 1 2*y-1 2y1是质数,那么区间就是 [ − 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][x1,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;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值