开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第5天,点击查看活动详情
今天来更新跟去年传智杯初赛有关的两道题,分别是小卡与质数1和小卡与质数2。说实话,做这两道题花费了我不少时间,虽然去年的传智杯比较水(),但是这两题还是学到了不少东西,补了补我比较薄弱的方面,话不多说,放题目了。
[传智杯 #4 初赛] 小卡和质数
题目背景
小卡最近迷上了质数,所以他想到了一个和质数有关的问题来考考你。
质数是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。
题目描述
小卡有 组询问。每次询问给你两个正整数 。
小卡想知道,第 个质数和第 个质数是否满足 ,即第 个质数和第 个质数的异或值是否是。
输入格式
第一行一个正整数 ,表示询问的数量。
接下来 行,每行两个正整数 ,表示询问的是第 个质数和第 个质数。
输出格式
行,每行一个字符串Yes或No,分别表示两个质数的异或值是 或不是 。
样例 #1
样例输入 #1
4
1 2
23 145
66 2
1 14
样例输出 #1
Yes
No
No
No
分析
其实我的位运算这块特别薄弱,所以一般看到位运算的题目,我就放弃,看到这题,其实我内心也想放弃,但是后来我试了几个数,发现除了2和3两个数异或值为1,其他的质数异或值都不为1,所以果断猜测,只有这一种为1的情况,然后提交了,后来上网一搜,发现只有相邻的两个数且奇数大的情况下,异或值为1。而质数,只有这一种情况满足,所以为只有这一种。
代码
#include <iostream>
#include <string>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <cstring>
#include <stack>
#include <cmath>
#include <algorithm>
using namespace std;
int cnt[110][1100],m[1100];
signed main(){
int t;
cin>>t;
while(t--){
int x,y;
cin>>x>>y;
if((x==2 && y==1) || (x==1 && y==2)) puts("Yes");
else puts("No");
}
//cout<<p<<endl;
}
下面是第二题小卡与质数2
[传智杯 #4 初赛] 小卡与质数2
题目背景
小卡迷上了质数!
题目描述
小卡最近迷上了质数,所以他想把任何一个数都转化为质数!
小卡有 次询问,每次给你一个数字 ,问有多少个比 小的非负整数 ,使得 是质数,其中 表示按位异或。
输入格式
第一行一个正整数 ,表示有 组询问。
接下来 行,每行一个正整数 。
输出格式
对于每组询问,输出一行一个整数,表示答案。
样例 #1
样例输入 #1
9
5
6
7
8
9
10
100
1000
10000
样例输出 #1
2
4
4
2
2
4
22
163
1132
其实在第一题之后,我又去了解了一下异或的其他性质,异或其实就是把两个数转化为二进制之后,对比两个二进制数相应的位,遵循同为0,异为1的原则,比如一个数和本身异或结果就是0,然后一个偶数^1=偶数+1,,可以推出,这题就用到了这个性质,还有个重要的性质,就是。
分析
这题我最先的想法是先用线性筛把2到200000之间所有的质数全部筛出来,然后运用上面那个性质,如果,那么答案。我本来以为这题的个询问就跟里面一样,不计入时间复杂度,但是是事实计入,所以我的这个代码复杂度是显然超时,,于是乎,我只能取评论区翻了一下,发现了一种奇妙的做法,只需要把我这个思路添加一点,我们很显然发现,要,我们就要想要满足什么样的条件呢,假设的二进制最高位为(一定是1),如果所对应的二进制数的第位是0,假设的二进制表示最高位比大,那么这一位异或结果是1,再看高于的其他位,因为的更高位肯定是0,所以的二进制表示的更高位就是和0异或,那么异或值肯定=本身。所以这个异或结果一定>。而反过来分析就会发现,如果所对应的二进制数的第位是1,那么显然,因此我们只需要统计每个质数的最高位,用一个数组记录最高位为且对应值为1的质数个数。然后我们只要遍历二进制位,如果这个位置为1,那么我们就加上相应的值。我们可以把的空间开大一点,开到31那么其实最后的复杂度就是,不会超时。 那么问题又来了,怎么快速找出一个二进制数的最高位是否为1呢,在今天之前我也不会,翻阅了大佬的发现了一个方法,如下图:
最后要记住,二进制是默认从0开始,所以最高位真正对应的要-1,最后奉上代码。
代码
#include <iostream>
#include <string>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <cstring>
#include <stack>
#include <cmath>
#include <algorithm>
using namespace std;
const int N=2000020;
int primes[N];
bool st[N];
int cnt=0;
int p=0;
int res[32];
inline void prime(int n){//线性筛
for(int i=2;i<=n;i++){
if(!st[i]){
primes[++cnt]=i;
p++;
}
for(int j=1;primes[j]<=n/i;j++){
st[primes[j]*i]=1;
if(i%primes[j]==0) break;
}
}
for(int i=1;i<=cnt;i++){
for(int j=30;j;j--){
if(primes[i]&(1<<(j-1))){
res[j]++;
break;
}
}
}
}
signed main(){
int x;
st[0]=1;
st[1]=1;
prime(N-10);
//cout<<p;
int t;
cin>>t;
while(t--){
int x;
scanf("%d",&x);
int ans=0;
for(int i=30;i;i--){
if(x&(1<<(i-1))) ans+=res[i];
}
printf("%d\n",ans);
}
}
希望能帮助到大家()!