第四届传智杯初赛_小卡与质数2
[传智杯 #4 初赛] 小卡与质数2
题目背景
小卡迷上了质数!
题目描述
小卡最近迷上了质数,所以他想把任何一个数都转化为质数!
小卡有 T T T 次询问,每次给你一个数字 x x x,问有多少个比 x x x 小的非负整数 y y y,使得 x ⊕ y x\oplus y x⊕y 是质数,其中 ⊕ \oplus ⊕ 表示按位异或。
输入格式
第一行一个正整数 T ( 1 ≤ T ≤ 1 0 5 ) T(1\le T\le10^5) T(1≤T≤105),表示有 T T T 组询问。
接下来 T T T 行,每行一个正整数 x ( 1 ≤ x ≤ 1 0 6 ) x(1\le x\le 10^6) x(1≤x≤106)。
输出格式
对于每组询问,输出一行一个整数,表示答案。
样例 #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)
x⊕y=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)
x⊕y=p→x⊕p=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 1⊕1=0
-
第一个 1 1 1
100100 ⊕ 1 ∗ ∗ ∗ ∗ ∗ = 0 ∗ ∗ ∗ ∗ ∗ < 100100 100100⊕ 1***** = 0***** <100100 100100⊕1∗∗∗∗∗=0∗∗∗∗∗<100100
换言之, 100100 ⊕ ( 100000 ∼ 111111 ) 100100⊕(100000 \sim 111111) 100100⊕(100000∼111111)的值都小于 100100 100100 100100
即, x ⊕ ( 2 5 ∼ 2 6 − 1 ) x⊕(2^5 \sim 2^6-1) x⊕(25∼26−1)
的值小于 x x x
现在我们只要算出 ( 2 5 ∼ 2 6 − 1 ) (2^5 \sim 2^6-1) (25∼26−1)
有几个质数即可,前缀和。 -
第二个 1 1 1
100100 ⊕ 0001 ∗ ∗ = 1000 ∗ ∗ < 100100 100100 ⊕ 0001** = 1000** <100100 100100⊕0001∗∗=1000∗∗<100100
换言之, 100100 ⊕ ( 000100 ∼ 000111 ) 100100⊕(000100 \sim 000111) 100100⊕(000100∼000111) 的值都小于 100100 100100 100100
即, x ⊕ ( 2 2 ∼ 2 3 − 1 ) x⊕(2^2 \sim 2^3-1) x⊕(22∼23−1)
的值小于 x x x
现在我们只要算出 ( 2 2 ∼ 2 3 − 1 ) (2^2 \sim 2^3-1) (22∼23−1) 有几个质数即可。
总之,若 x x x 的第 i i i 位为 1 1 1,算出 2 i ∼ 2 i + 1 − 1 2^i \sim 2^{i+1}-1 2i∼2i+1−1有多少个质数累加即可。
注意, x ⊕ p = y ( y < x ) x⊕p=y(y < x) x⊕p=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;
}