P8036 [COCI2015-2016#7] Prosti 题解
题目分析
我太菜了,只会打表,但是打表也要优雅!(正解似乎是二分)
一看数据范围如此之小,才 \(150\) 打表肯定可以鸭!
把考虑两种情况:
- 连续区间中有小于等于 \(m\) 的数。
- 没有小于 \(m\) 的,即全是大于 \(m\) 的质数。
前者可以在每个询问中得到,或者为了方便,所有的起点小于 \(150\) 的答案都在每个询问中单独完成。
code:
int sol(int k,int l,int m){
int cnt=0;
for(int i=1;i<=k;++i)
if(i<=m || !vi[i]) ++cnt;
if(cnt==l) return 1;
for(int i=1;i<150;++i){
if(i<=m || !vi[i]) --cnt;
if(i+k<=m || !vi[i+k]) ++cnt;
if(cnt==l) return i+1;
}
return -1;
}
对于情况 \(2\) 考虑先处理出 \(10^7\) 以内所有质数,然后枚举 \(10^7\) 内所有长度小于等于 \(150\) 的区间,并且统计其中的高兴数的个数。
这里为了方便用,令 st[i][j]
表示连续 \(i\) 个数中有 \(j\) 个高兴数的起点。
code:
memset(st,-1,sizeof st);
for(int i=1;i<=150;++i){
int cnt=0;
for(int j=151;j<=150+i;++j)
if(!vi[j]) ++cnt;
st[i][cnt]=151;
for(int j=151;j<=5e5;++j){
if(!vi[j]) --cnt;
if(!vi[j+i]) ++cnt;
if(st[i][cnt]==-1) st[i][cnt]=j+1;
}
}
再输出,就得到了一张表,这样答案就可以很快得到了。但是直接复制会有点大,代码也不美观。
仔细观察可以发现,表中的答案只有 st[138~150][1]
的结果是大于 \(5\times 10^5\) 的,而 \(0.5s\) 的时限也只支持枚举到 \(5\times10^5\)。
所以我们在程序中只需要枚举到 \(5\times10^5\) 即可,再直接把上面得到的值赋给对应的就好了。
main 函数 code:
int main(){
pri();//线性筛
memset(st,-1,sizeof st);
for(int i=1;i<=150;++i){
int cnt=0;
for(int j=151;j<=150+i;++j)
if(!vi[j]) ++cnt;
st[i][cnt]=151;
for(int j=151;j<=5e5;++j){
if(!vi[j]) --cnt;
if(!vi[j+i]) ++cnt;
if(st[i][cnt]==-1) st[i][cnt]=j+1;
}
}
st[138][1]=1357194;
st[139][1]=1357194;
for(int i=140;i<=150;++i) st[i][1]=1561892;//打表得到的值
int q=read();
while(q--){
int k=read(),l=read(),m=read();
int tmp=sol(k,l,m);//上面给了代码的
if(tmp!=-1) printf("%d\n",tmp);
else printf("%d\n",st[k][l]);
}
return 0;
}
至此,打表的方法完美通过。