题目描述
现在有一排共N个数,你需要从中选出恰好K个。选出K个数后,计算它们两两差值的绝对值的最小值S。你需要确定选出哪K个,才能最大化这个S。
输入数据
输入第一行两个正整数N、K,含义如上。 输入第二行N个正整数,依次表示这N个数A1~An。0<Ai≤10^9。
输出数据
一行一个正整数,S的最大值。
样例输入
11 5
19 585 29 1111 5868 3331 272 4441 2251 868 581
样例输出
1092
数据范围
对于30%30%的数据,N≤18N≤18。
对于60%60%的数据,N≤20N≤20。
对于80%80%的数据,N≤100N≤100。
对于100%100%的数据,N≤100000,K<=NN≤100000,K<=N
题目分析
话说我们上次的那道题,难度应该是NOIP第六题水平了,双向SPFA负环割边fread读优。我们迎来了一道数论题。我们看完题目,一脸懵逼。然后发现“最大的最小,最小的最大”,发现这是一道整体二分。于是我就一遍AC了这道水题。
代码实现
#include<bits/stdc++.h> using namespace std; #define RE register int #define IL inline #define N 100001 int n,k,a[N],minn=1e9,maxx; inline char gc(){ static char buf[100001],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100001,stdin),p1==p2)?EOF:*p1++; }template<class T>inline int read(T&x){ x=0;register char c=gc(); while(c<48)c=gc(); while(c>47)x=(x<<1)+(x<<3)+(c^48),c=gc(); }void write(RE x){ if (x>9)write(x/10); putchar(x%10^48); }inline int check(RE x){ RE sum=1,temp=a[1]; for (RE i=2;i<=n;++i) if (a[i]>=temp+x) sum++,temp=a[i]; return sum>=k; }signed main(){ freopen("choose.in","r",stdin),freopen("choose.out","w",stdout); cin>>n>>k; for (RE i=1;i<=n;++i) cin>>a[i],maxx=max(maxx,a[i]),minn=min(minn,a[i]); sort(a+1,a+n+1); RE r=maxx,l=minn,m,ans=0; while(l<=r) check(m=(l+r)>>1)?ans=m,l=m+1:r=m-1; write(ans); return 0; }
代码说明
现在二分答案分为很多个流派,我们学校的许多同学是降临派,我是拯救派,我们已经不流行幸存派了。。。
读者:你个SB,还给我扯,三体看多了吧。
就是说在二分的时候几率答案,二分的方法很多,我不予以展开。这道题的难度啊,NOIP的第二题难度,我5分钟A掉。
原文地址:https://www.cnblogs.com/aserrrre/p/10568919.html
时间: 2024-10-31 16:51:20