题目:小卡与质数2
Description
小卡最近迷上了质数,所以他想把任何一个数都转化为质数!
小卡有 T 次询问,每次给你一个数字 x,问有多少个比 x 小的非负整数 y,使得 x⊕y 是质数,其中 ⊕ 表示按位异或。
Input
第一行一个正整数 T(1≤T≤105),表示有 T 组询问。
接下来 T 行,每行一个正整数 x(1≤x≤106)。
Output
对于每组询问,输出一行一个整数,表示答案。
Sample
输入
9
5
6
7
8
9
10
100
1000
10000
输出
2
4
4
2
2
4
22
163
1132
Solution
- 非负整数 x 与小于自身的非负整数异或得到的结果都不相同
- 非负整数 x 与小于自身的非负整数异或得到的结果必定小于 2x
- 非负整数 x = (1000…000)2 与小于自身的非负整数异或,值域为[1000…000, 1111…111],即[x, x2-1],例:x = 4 = (100)2
- 非负整数 x = (1xxx…xxx)2 与小于(1000…000)2的非负整数异或,[1000…000, 1111…111]是值域的子集,即[x, x2-1]是值域的子集,例:x = 6 = (110)2
- 非负整数 x 与小于自身的非负整数异或,若 x 的二进制数在某位上为1,如(…1…),那么[0001000, 0001111]是值域的子集
通过二进制枚举 x 的每一个位,求出各个值域子集内质数的个数之和。
例子:
x = 6 = (110)2
110 ^ 000 = 110 = 6
110 ^ 001 = 111 = 7
110 ^ 010 = 100 = 4
110 ^ 011 = 101 = 5
110 ^ 100 = 010 = 3
110 ^ 101 = 011 = 2
菜鸡不会严格的证明:(大家有什么其他好的方法也欢迎分享
AC Code
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <math.h>
using namespace std;
const int M = 5000001;
int a[M] = {0};
//判断是否为素数
bool prime(int num) {
if (num == 1)
return 0;
if (num == 2 || num == 3)
return 1;
if (num % 6 != 1 && num % 6 != 5)
return 0;
int tmp = sqrt(num);
for (int i = 5; i <= tmp; i += 6)
if (num % i == 0 || num % (i + 2) == 0)
return 0;
return 1;
}
int main() {
// a[i] 表示[1, i]内质数的个数
for(int i = 1; i <= M; i++) {
a[i] = a[i-1];
if(prime(i)) {
++ a[i];
}
}
int t;
cin >> t;
while(t--) {
int num = 0;
int x;
cin >> x;
// 二进制枚举
int f = 1;
while(f <= x) {
int ls = f & x;
// cout << "f = " << f << " x = " << x;
// cout << "ls = " << ls << endl;
if(ls > 0) {
int rs = (ls << 1);
num += a[rs-1] - a[ls-1];
}
f <<= 1;
}
cout << num << endl;
}
return 0;
}