[USACO11NOV]牛的陣容Cow Lineup
【問題描述】
農民約翰僱一個專業攝影師給他的部分牛拍照。由於約翰的牛有好多品種,他喜歡他的照片包含每
個品種的至少一頭牛。
約翰的牛都站在一條沿線的不同地方, 每一頭牛由一個整數位置 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;
}