【复赛模拟试题】奶牛卧室 筛法

来源:互联网 发布:图解网络硬件二手书 编辑:程序博客网 时间:2024/04/28 02:25

【问题描述】

  奶牛们有一个习惯,那就是根据自己的编号选择床号。如果一头奶牛编号是a,并且有0..k-1一共k张床,那么她就会选择a mod k号床作为她睡觉的地点。显然,2头牛不能睡在一张床上。那么给出一些奶牛的编号,请你为她们准备一间卧室,使得里面的床的个数最少。

【输入格式】

  第一行是奶牛的个数n(1<=n<=5000);
  第2到第n+1行是每头奶牛的编号Si(1<=Si<=1000000)。

【输出格式】

仅一行,是最少的床的数目。

【输入样例】

5
4
6
9
10
13

【输出样例】

8

【数据范围】

n<=5000

——————————————————————————————————————————————

先来观察什么样的情况下有两只奶牛睡在同一张床上。显然当两只奶牛要求的差是k的倍数,即k是两只奶牛要求的差的因数的时候她们会睡在一起。也就是说现在的问题转化为了怎么样快速求出不是任何一个数因数的数。

首先发现n^2可以远远大于10^6,也就是说这个时候肯定会有很多的差安置是重复的。那么只需要标记一下出现过的差值就可以完成一个剪枝。
显然不可以分解因数啊,一分解就太慢了。不管怎么剪枝都会超时的。这个时候我们想到了筛法,枚举每个数作为最后的答案,看这个数的倍数有没有被标记过。第一个没有被标记过的数就是答案。

时间复杂度为O(maxs/1+maxs/2+……+maxs/maxs)=O(maxs*(1+1/2+……+1/maxs))=O(maxs * lnmaxs);

AC代码:

#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>#include<algorithm>#include<cmath>#include<queue>#include<set>#include<map>#include<vector>#include<cctype>using namespace std;const int maxn=5005;const int maxs=1000005;int N,a[maxn];int delt[maxs],cnt,MAX;bool mark[maxs];void _scanf(int &x){    x=0;    char ch=getchar();    while(ch<'0'||ch>'9') ch=getchar();    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();}void data_in(){    _scanf(N);    for(int i=1;i<=N;i++)        _scanf(a[i]),MAX=max(MAX,a[i]);}void work(){    for(int i=1;i<N;i++)    for(int j=i+1;j<=N;j++)        mark[abs(a[i]-a[j])]=1;    int ans=N;    while(1)    {        bool ok=1;        for(int i=1;i*ans<=MAX;i++)            if(mark[i*ans]) { ok=0; break; }        if(ok) break;        ans++;    }    printf("%d\n",ans);}int main(){    freopen("test.in","r",stdin);    freopen("test.out","w",stdout);    data_in();    work();    return 0;}
原创粉丝点击