[USACO11NOV]牛的阵容Cow Lineup

来源:互联网 发布:做皮卡剧的软件 编辑:程序博客网 时间:2024/04/28 05:49

【问题描述】

农民约翰雇一个专业摄影师给他的部分牛拍照。由于约翰的牛有好多品种,他喜欢他的照片包含每个品种的至少一头牛。

约翰的牛都站在一条沿线的不同地方, 每一头牛由一个整数位置 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;

对于牛的编号,我们发现牛的编号最大会到1亿,但对于那么大的数值,我们就不能利用桶来判断所有编号的牛是否都被拍在这张照片里了。所以,我们要通过hash来缩小牛的编号,在这里,我对于数值hash的值为6000,当然,也可以是其他值。

当然,你也发现,牛的位置是无序的,你想到了什么?当然是一个快排!

然后,我们用一重循环来枚举这张照片的左端点的牛,另外还有一个变量记录这张照片的右端点。这个右端点肯定不能一次次从第一头牛开始往后扫,我们要沿着上一次到达的牛继续往后扫,知道满足题目的条件为止。

var n,s,i,x,y,ans:longint;     a,b:array[1..50005]of longint;    f:array[0..70000,0..1]of longint;//为hash服务    t:array[0..70000]of longint;//这是一个桶,用来统计当前的牛的头数,这对于后面的计算有多少头牛在这张照片里面是十分重要的。procedure qsort(l,r:longint);//快排var i,j,mid,t,t1:longint;begin  i:=l;j:=r;mid:=(i+j)div 2;  t:=a[mid];t1:=b[mid];  a[mid]:=a[l];b[mid]:=b[l];  while i<j do    begin      while (i<j)and(a[j]>t) do dec(j);      if i<j then        begin          a[i]:=a[j];b[i]:=b[j];inc(i);        end;      while (i<j)and(a[i]<t) do inc(i);      if i<j then        begin          a[j]:=a[i];b[j]:=b[i];dec(j);        end;    end;  a[i]:=t;b[i]:=t1;  if i+1<r then qsort(i+1,r);  if i-1>l then qsort(l,i-1);end;function hash(x:longint):longint;//hash处理var j:longint;begin  j:=x mod 60000;  while f[j,0]<>x and f[j,0] do    begin      j:=j+1;      j:=j mod 60000;    end;  if f[j,0]=0 then    begin      s:=s+1;f[j,1]:=s;f[j,0]:=x;    end;   exit(f[j,1]);end;begin  readln(n);  for i:=1 to n do     begin      readln(a[i],b[i]);      b[i]:=hash(b[i]);//牛的编号进行hash处理    end;  qsort(1,n);//对于牛的位置进行排序  x:=1;y:=1;inc(t[b[1]]);ans:=-1;//预处理  for i:=1 to n do    begin      while (x<s)and(y<n) do//所有种数的牛还没有都在这张照片并且我们还没有枚举完所有的奶牛。        begin          inc(y);inc(t[b[y]]);//加上这头牛的种类          if t[b[y]]=1 then inc(x);//如果这头牛在这张照片第一次出现,说明这张照片中有出现一种新的奶牛。        end;      if ((ans=-1)or(ans>a[y]-a[i]))and(x=s) then//如果ans是-1,或者当前的照片的长度比我们以前求出的最优值小,并且所有种类的牛都出现在这张照片中,就立即更新。        ans:=a[y]-a[i];      dec(t[b[i]]);//把当前最左端的牛从这张照片中去除。      if t[b[i]]=0 then dec(x);//如果最左端的这种牛在照片中没了,不同的牛数就-1。    end;  writeln(ans);end.