题解:P17733 [ICPC 2019 Xuzhou R] <3 numbers

· · 题解

不难看出“<3 数”构成的集合其实就是质数集 \cup \{1\},所以就是在问你一个区间内质数占比是否 <\frac{1}{3},可以考虑先欧拉质数筛预处理,但是对于

~~众所周知~~,质数有个特性就是越往后其占比越稀疏,而当 $L>10^6$ 或 $R>10^6$ 时其稀疏程度已经可以保证 $< \frac{1}{3}$ 了,但是此处还要特判极小区间长度 $1$,$2$,$3$ 的情况,此处可采用如下普通判断质数方式来逐个判断该极小区间内的质数。 ``` bool isPrime(int x){ int sx=sqrt(x); if(x<2) return false; if(x==2) return true; if(x%2==0) return false; for(int i=3;i<=sx;i+=2){ if(x%i==0) return false; } return true; } ``` 该判断算法时间复杂度 $O(\sqrt{n})$。 综上,仅先质数筛处理 $[2,10^6]$,若 $\le 10^6$ 就先用 `lower_bound` 求出第一个区间内的质数,再往后判断筛出来的质数直到超出区间,统计看是否 $<\frac{1}{3}$ 即可。若 $>10^6$ 则先特判极小区间,其余情况均 $<\frac{1}{3}$,直接输出 `Yes`。 记得 $1$ 也是“$<3$ 数”。 完整代码如下。 ```cpp #include<bits/stdc++.h> using namespace std; #define M 1000002 #define int long long vector<int> primes; bool noprime[M]; void p(){ for(int i=2;i<=M;i++){ if(!noprime[i]) { primes.push_back(i); } for(auto p:primes){ if(i*p>M) break; noprime[i*p]=true; if(i%p==0) break; } } } bool isPrime(int x){ int sx=sqrt(x); if(x<2) return false; if(x==2) return true; if(x%2==0) return false; for(int i=3;i<=sx;i+=2){ if(x%i==0) return false; } return true; } signed main(){ ios::sync_with_stdio(false); cin.tie(0); int T; cin>>T; p(); while(T--){ int cnt=0; int l,r,lr; cin>>l>>r; if(l<=1e6&&r<=1e6){ int di=lower_bound(primes.begin(),primes.end(),l)-primes.begin(); while(primes[di]<=r){ cnt++; di++; } if(l==1) cnt++; int x=r-l+1; if(3*cnt<x) cout<<"Yes\n"; else cout<<"No\n"; } else{ if(r-l+1==1){ if(isPrime(l)) cout<<"No\n"; else cout<<"Yes\n"; } else if(r-l+1==2){ bool hf=false; if(l%2) hf=!isPrime(l); else hf=!isPrime(r); if(hf) cout<<"Yes\n"; else cout<<"No\n"; } else if(r-l+1==3){ bool hf=!isPrime(l) and !isPrime(l+1) and !isPrime(l+2); if(hf) cout<<"Yes\n"; else cout<<"No\n"; } else{ cout<<"Yes\n"; } } } } ``` ~~代码是队友码的所以和我码风差别很大。~~