usaco2016open bronze1 diamond

     Diamond Collector(Bronze)

奶牛Bessie很喜欢闪亮亮的东西(Baling~Baling~),所以她喜欢在她的空余时间开采钻石!她现在已经收集了N颗不同大小的钻石(N<=1000),现在她想在谷仓的陈列架上摆放一些钻石。

    Bessie想让这些陈列架上的钻石保持相似的大小,所以她不会把两个大小相差K以上的钻石同时放在陈列架上(如果两颗钻石的大小差值为K,那么它们可以同时放在陈列架上)。现在给出K,请你帮Bessie确定她最多可以放多少颗钻石在陈列架上。

 

输入格式(diamond.in:

    第一行输入两个值NK0<=K<10,000)

接下来N行,每行是一个整数,分别表示第1~N颗钻石的大小。

数据保证钻石的大小为正数且不超过10,000.

 

输出格式(diamond.out):

输出仅一个数,为Bessie能在陈列架上摆的钻石数的最大值。

 

输入样例:

5 3

1

6

4

3

1

 

输出样例:

4

================================================================

题目可以简述为:n 个不同的数,现在选取某些数组成序列 a1..am,要求对于任意的 i j 满足 abs(ai-aj)<=k,问这样的序列最大长度是多少.
因为数据范围很小,n<=1000,完全可以用 O(n^2)的算法解决:先枚举每一个数,作为答案序列中最小的数,再看其他数和它的差是否在 k 以内,是就加入序列.这是因为:既然序列中最小的数和最大的数的差都不超过 k,自然其他数两两之间的差也不会大于 k.
代码如下:

 
   

#include
#include
const int SIZE=1e4+5;
int N,K,a[SIZE];
inline int max(int x,int y){
return x>y?x:y;
}
int main() {
freopen("diamond.in","r",stdin);
freopen("diamond.out","w",stdout);
scanf("%d%d",&N,&K);
for(int i=0;i!=N;++i)scanf("%d",&a[i]);
int ans=0;
for(int i=0;i!=N;++i){
int cnt=0;
for(int j=0;j!=N;++j)
if(a[i]<=a[j]&&a[j]<=a[i]+K)++cnt;
ans=max(ans,cnt);
}
printf("%d\n",ans);
return 0;
}

  Update:我们发现钻石的大小范围也很小,最多 10000,因此还可以考虑另外一种做法:计数排序统计每个大小的钻石数量,枚举最小的钻石大小 x,那么大小位于[x,x+k]范围内的钻石数量即为这种情况下的解.在已经计数排序的情况下,如何快速求出大小在某个范围内的钻石数?
部分和可以轻松解决.时间复杂度 O(maxSize),本题中即 maxSize=10000.
代码如下:

 
    

#include
using namespace std;
const int maxk=10005;
ifstream fin("diamond.in");
ofstream fout("diamond.out");
int n,k,f[maxk],sum[maxk];
int main(){
fin>>n>>k;
for(int i=0;i!=n;++i){
int size;
fin>>size;
++f[size];
}
for(int i=1;i!=10001;++i)sum[i]=sum[i-1]+f[i];
int ans=0;
for(int i=1;i+k!=10001;++i)ans=max(ans,sum[i+k]-sum[i-1]);
fout< return 0;
}

你可能感兴趣的:(解题报告,单调队列,USACO,前缀和)