[NOIP2021] 报数 题解
[NOIP2021] 报数 题解
知识点
埃氏筛,离线。
分析
首先暴力很简单,直接枚举强行判断即可。
接下来考虑优化,发现 \(1 \le x \le 10^7\),那么完全是可以预处理出来的。
模仿埃氏筛,会得到一个常数极小的筛法,时间复杂度大概 \(O(X\log_{2}{\log_{2}{X}})\)。
(你想欧拉筛也可以试试,但是 std::bitset 与 std::vector 配合埃氏筛是实际效率最高的。)
然后我们可以直接二分来查询答案,但是有超时的风险,所以离线后尺取即可。
代码
时间复杂度:\(O(X\log_2{\log_2{X}} + T)\),空间复杂度:\(O(\frac{X}{w}+T)\),其中 \(w=32\)。
#define Plus_Cat "number"
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define Fi first
#define Se second
#define ll long long
#define Pii pair<int,int>
#define RCL(a,b,c,d) memset(a,b,sizeof(c)*(d))
#define FOR(i,a,b) for(int i(a);i<=(int)(b);++i)
#define DOR(i,a,b) for(int i(a);i>=(int)(b);--i)
#define tomin(a,...) ((a)=min({(a),__VA_ARGS__}))
#define tomax(a,...) ((a)=max({(a),__VA_ARGS__}))
#define EDGE(g,i,x,y) for(int i(g.h[x]),y(g[i].v);~i;y=g[i=g[i].nxt].v)
using namespace std;
constexpr int N(1e7+10),Qr(2e5+10);
bitset<N> f;
bool p(int x) {
for(; x; x/=10)if(x%10==7)return 1;
return 0;
}
void Init(int n=N-5) {
FOR(i,7,n)if(!f[i]) {
if(i%7==0) {
f[i]=1;
continue;
}
if(p(i))for(int j(i); j<=n; j+=i)f[j]=1;
}
}
int Q;
namespace Subtask_Online {
bool Check() {
return Q<=100;
}
void Query() {
FOR(i,1,Q) {
int x;
scanf("%d",&x);
if(f[x])puts("-1");
else {
do ++x;
while(f[x]);
printf("%d\n",x);
}
}
}
int Cmain() {
Init();
Query();
return 0;
}
}
namespace Subtask_All {
int tot;
int ans[Qr];
Pii qr[Qr];
void Scan() {
FOR(i,1,Q) {
int x;
scanf("%d",&x);
if(f[x])ans[i]=-1;
else qr[++tot]=Pii(x,i);
}
sort(qr+1,qr+tot+1);
}
void Solve(int n=N-5) {
int it(1);
FOR(i,1,n)if(!f[i]) {
while(it<=tot&&qr[it].Fi<i)ans[qr[it].Se]=i,++it;
if(it>tot)break;
}
}
void Print() {
FOR(i,1,Q)printf("%d\n",ans[i]);
}
int Cmain() {
Init();
Scan();
Solve();
Print();
return 0;
}
}
int main() {
#ifdef Plus_Cat
freopen(Plus_Cat ".in","r",stdin),freopen(Plus_Cat ".out","w",stdout);
#endif
scanf("%d",&Q);
if(Subtask_Online::Check())return Subtask_Online::Cmain();
return Subtask_All::Cmain();
}

浙公网安备 33010602011771号