【问题描述】
农民约翰雇一个专业摄影师给他的部分牛拍照。由于约翰的牛有好多品种,他喜欢他的照片包含每
个品种的至少一头牛。
约翰的牛都站在一条沿线的不同地方, 每一头牛由一个整数位置 X_i以及整数品种编号 ID_i表示。
约翰想拍一张照片,这照片由沿线的奶牛的连续范围组成。照片的成本与规模相当,这就意味着,在一
系列照片中的最大和最小 X 坐标的差距决定了照片的成本。
请帮助约翰计算最小的照片成本,这些照片中有每个不同的品种的至少一头牛,没有两头牛愿意站
在同一个地点的。
【输入格式】
第 1 行:牛的数量 N;
第 2..1+N 行:每行包含 2 个以空格分隔的正整数 X_i 和 ID_i;意义如题目描述;
【输出格式】
输出共一行,包含每个不同品种 ID 的照片的最低成本。
【输入样例】
6 25 7 26 1 15 1 22 3 20 1 30 1
【输出样例】
4
【输入说明】
在不同的坐标点 25,26,15,22,20,30 中有六头牛
【输出说明】
在约翰的牛中,从 X=22 到 X=26(整个规模为 4)包含了每个的不同品种的 ID 3,7 和 1。
【数据规模】
对于 50%的数据: 1≤N≤300;
对于 100%的数据:1≤N≤50,000;0≤X_i≤1,000,000,000;1≤ID_i≤1,000,000,000;
刚刚看到这一题,觉得不是很难,但是一做起来,就感觉束手无策,看了一下数据范围,我感觉做法应该是O(n)或者是O(n^logn)
因为这一道题必须要排序,所以直接排除O(n)的做法
因为品种数量很大,所以要给di离散一下,可以省掉map
我想了想,决定用两个指针,分别指向左右两端,左指针for循环,右指针指向刚刚好能满足条件的那个点,并且多次记录最大值
查找时间为O(n),加上快排O(nlogn)
也可能是我看到xi<=10^9的原因吧,我竟然用了一个二分,查找时间是O(30n),因为30是常数所以时间还是O(N),
代码
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x=0,f=0;char s=getchar();
while(!isdigit(s))f|=s=='-',s=getchar();
while( isdigit(s))x=(x<<1)+(x<<3)+s-48,s=getchar();
return !f?x:-x;
}
const int N=5e4+20;
struct node{
int x,d;
inline bool operator<(const node &k)const{
return x<k.x;
}
}a[N];int n;
struct LSnode{
int x,z,p;
inline bool operator<(const LSnode &k)const{
return x<k.x;
}
}b[N];
int bk[N];
inline bool check(int x){
memset(bk,0,sizeof(bk));
int p2=1,ans=1;bk[a[1].d]=1;
for(int p1=1;p1<=n;p1++){
if(p2==n)break;
while(a[p2+1].x-a[p1].x<=x&&p2<n){
p2++;bk[a[p2].d]++;
if(bk[a[p2].d]==1)ans++;
}
if(ans==b[n].z)return 1;
bk[a[p1].d]--;
if(!bk[a[p1].d])ans--;
}
return 0;
}
int main(){
n=read();
for(int i=1;i<=n;i++){
a[i].x=read();a[i].d=read();
b[i].x=a[i].d;b[i].p=i;
}
sort(b+1,b+n+1);//离散化
b[1].z=1;
for(int i=2;i<=n;i++)b[i].z=b[i-1].z+(b[i].x==b[i-1].x?0:1);
for(int i=1;i<=n;i++)a[b[i].p].d=b[i].z;
sort(a+1,a+n+1);
int l=0,r=1e9,mid,ans=-1;//二分
while(l<=r){
mid=(l+r)>>1;
if(check(mid))ans=mid,r=mid-1;
else l=mid+1;
}
printf("%d\n",ans);
return 0;
}
打完二分以后突然发现里面的check似乎可以直接用来求最小值,于是我又打了一个不用二分的程序
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x=0,f=0;char s=getchar();
while(!isdigit(s))f|=s=='-',s=getchar();
while( isdigit(s))x=(x<<1)+(x<<3)+s-48,s=getchar();
return !f?x:-x;
}
const int N=5e4+20;
struct node{
int x,d;
inline bool operator<(const node &k)const{
return x<k.x;
}
}a[N];int n;
struct LSnode{
int x,z,p;
inline bool operator<(const LSnode &k)const{
return x<k.x;
}
}b[N];
int bk[N];
int main(){
n=read();
for(int i=1;i<=n;i++){
a[i].x=read();a[i].d=read();
b[i].x=a[i].d;b[i].p=i;
}
sort(b+1,b+n+1);
b[1].z=1;
for(int i=2;i<=n;i++)b[i].z=b[i-1].z+(b[i].x==b[i-1].x?0:1);
for(int i=1;i<=n;i++)a[b[i].p].d=b[i].z;
sort(a+1,a+n+1);
int p2=1,ans=1;bk[a[1].d]=1;
int minn=1e9+10;
for(int p1=1;p1<=n;p1++){
while(p2<n&&ans<b[n].z){
p2++;bk[a[p2].d]++;
if(bk[a[p2].d]==1)ans++;
}
if(ans<b[n].z)break;
minn=min(minn,a[p2].x-a[p1].x);
bk[a[p1].d]--;
if(!bk[a[p1].d])ans--;
}
printf("%d\n",minn);
return 0;
}