第四届传智杯初赛_小卡与质数2

这篇博客介绍了如何利用位操作和前缀和算法高效地解决寻找小于给定数的非负整数异或后为质数的问题。博主通过分析发现,当对一个数进行异或操作时,如果异或的目标是该数二进制表示中1的位置,那么结果会小于原数。因此,可以通过计算每个二进制位为1时对应的质数数量并累加来得出答案。博主提供了C++代码实现,并展示了样例输入和输出,强调了时间复杂度和空间复杂度的优化技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[传智杯 #4 初赛] 小卡与质数2

题目背景

小卡迷上了质数!

题目描述

小卡最近迷上了质数,所以他想把任何一个数都转化为质数!

小卡有 T T T 次询问,每次给你一个数字 x x x,问有多少个比 x x x 小的非负整数 y y y,使得 x ⊕ y x\oplus y xy 是质数,其中 ⊕ \oplus 表示按位异或。

输入格式

第一行一个正整数 T ( 1 ≤ T ≤ 1 0 5 ) T(1\le T\le10^5) T(1T105),表示有 T T T 组询问。

接下来 T T T 行,每行一个正整数 x ( 1 ≤ x ≤ 1 0 6 ) x(1\le x\le 10^6) x(1x106)

输出格式

对于每组询问,输出一行一个整数,表示答案。

样例 #1

样例输入 #1

9
5
6
7
8
9
10
100
1000
10000

样例输出 #1

2
4
4
2
2
4
22
163
1132

算法(思维,二进制,素数筛,前缀和)

x ⊕ y = p ( y < x ) x⊕y=p (y < x) xy=p(y<x)
要枚举 y y y,时间复杂度 O ( T x ) O(Tx) O(Tx)
x ⊕ y = p → x ⊕ p = y ( y < x ) x⊕y=p \to x⊕p=y(y < x) xy=pxp=y(y<x)
要枚举 p p p ,时间复杂度 O ( T z ) O(Tz) O(Tz) 。百万内的质数有 z z z个(几万)。
因为 y < x y<x y<x,异或后值变小。什么情况异或后值会变小?
x = ( 100100 ) 2 x=(100100)_2 x=(100100)2
要想异或后值变小, 1 1 1必须变成 0 0 0

1 ⊕ 1 = 0 1⊕1=0 11=0

  • 第一个 1 1 1
    100100 ⊕ 1 ∗ ∗ ∗ ∗ ∗ = 0 ∗ ∗ ∗ ∗ ∗ < 100100 100100⊕ 1***** = 0***** <100100 1001001=0<100100
    换言之, 100100 ⊕ ( 100000 ∼ 111111 ) 100100⊕(100000 \sim 111111) 100100(100000111111)的值都小于 100100 100100 100100
    即, x ⊕ ( 2 5 ∼ 2 6 − 1 ) x⊕(2^5 \sim 2^6-1) x(25261)
    的值小于 x x x
    现在我们只要算出 ( 2 5 ∼ 2 6 − 1 ) (2^5 \sim 2^6-1) (25261)
    有几个质数即可,前缀和。

  • 第二个 1 1 1
    100100 ⊕ 0001 ∗ ∗ = 1000 ∗ ∗ < 100100 100100 ⊕ 0001** = 1000** <100100 1001000001=1000<100100
    换言之, 100100 ⊕ ( 000100 ∼ 000111 ) 100100⊕(000100 \sim 000111) 100100(000100000111) 的值都小于 100100 100100 100100
    即, x ⊕ ( 2 2 ∼ 2 3 − 1 ) x⊕(2^2 \sim 2^3-1) x(22231)
    的值小于 x x x
    现在我们只要算出 ( 2 2 ∼ 2 3 − 1 ) (2^2 \sim 2^3-1) (22231) 有几个质数即可。

总之,若 x x x 的第 i i i 位为 1 1 1,算出 2 i ∼ 2 i + 1 − 1 2^i \sim 2^{i+1}-1 2i2i+11有多少个质数累加即可。

注意, x ⊕ p = y ( y < x ) x⊕p=y(y < x) xp=y(y<x) p p p 有可能超过 x x x

代码(C++)

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 2e6 + 10;

bool st[N];
int s[N];

int lowbit(int x)
{
	return x & -x;
}

void get_prefix()
{
	st[0] = st[1] = 1;
	for(int i = 2; i <= N - 10; i ++)
	{
		if(st[i]) continue;
		for(int j = i + i; j <= N - 10; j += i) st[j] = 1;
	}
	
	for(int i = 1; i <= N - 10; i ++) s[i] = s[i - 1] + (!st[i]);
}

int main()
{
	
	get_prefix();
	
	int T;
	scanf("%d", &T);
	while(T --)
	{
		int x;
        scanf("%d", &x);
        
        int res = 0;
        while(x)
        {
        	int t = lowbit(x);
        	res += s[(t << 1) - 1] - s[t - 1];
			x -= t;
		}
		cout << res << endl;
	}
	
	return 0;
}
为了在2022第五届初赛中取得优异成绩,高效地复习算法和数据结构知识至关重要。推荐使用《2022第五届初赛赛题解析技术要点》这一资源,因为它详细解析了比赛中的关键题目和解题思路,有助于你快速定位自己的薄弱环节并加以强化。复习时,请按照以下步骤进行: 参考资源链接:[2022第五届初赛赛题解析技术要点](https://wenku.youkuaiyun.com/doc/7h56xub0jg?spm=1055.2569.3001.10343) 1. 理解题目要求:首先仔细阅读赛题文档,理解每个题目的具体要求和限制条件,确保对问题有清晰的认识。 2. 分类复习:将赛题按照算法和数据结构的类型进行分类,比如排序算法、图论算法、动态规划等,这样可以帮助你系统地复习。 3. 深入学习:对于每一类算法和数据结构,深入研究其原理、应用场景和常见问题。例如,动态规划问题通常需要分析最优子结构、边界条件和状态转移方程。 4. 实践编程:实际编写代码来解决赛题,这不仅加深理解,还能提高编码能力。建议在编程时多尝试不同的算法和数据结构,找到最优解。 5. 错题回顾:遇到问题或错误时,要及时回顾相关知识点,并查看《2022第五届初赛赛题解析技术要点》中的解析,从中学习解题技巧和优化思路。 6. 时间管理:练习时注意时间管理,尽量在规定时间内完成题目,模拟考试场景,以适应竞赛的时间压力。 通过上述步骤,结合《2022第五届初赛赛题解析技术要点》这本资料,相信你能更有效地复习,为比赛做好充分准备。祝你在初赛中取得好成绩! 参考资源链接:[2022第五届初赛赛题解析技术要点](https://wenku.youkuaiyun.com/doc/7h56xub0jg?spm=1055.2569.3001.10343)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值