BZOJ1701 : [Usaco2007 Jan]Cow School牛学校

枚举剩下的分数个数$k$,设最高的$k$个分数和的分子分母分别为$U$和$D$。

那么在选了的里面找到$A=\min(Dt[x]-Up[x])$,没选的里面找到$B=\max(Dt[x]-Up[x])$。

如果$A<B$,则可以更大。

对于$A,B$的计算,可以利用决策单调性分治求解。

时间复杂度$O(n\log n)$。

#include<cstdio>
#include<algorithm>
typedef long long ll;
const int N=50010;
const ll inf=1LL<<60;
int n,i,ans,q[N];ll f[N],g[N];
struct P{int t,p;}a[N],b[N];
inline bool cmp(const P&a,const P&b){return a.t*b.p>b.t*a.p;}
void getf(int l,int r,int dl,int dr){
  int m=(l+r)>>1,dm;
  f[m]=inf;
  for(int i=dl;i<=m&&i<=dr;i++){
    ll t=1LL*a[i].t*b[m].p-1LL*a[i].p*b[m].t;
    if(t<f[m])f[m]=t,dm=i;
  }
  if(l<m)getf(l,m-1,dl,dm);
  if(r>m)getf(m+1,r,dm,dr);
}
void getg(int l,int r,int dl,int dr){
  int m=(l+r)>>1,dm;
  g[m]=-inf;
  for(int i=dr;i>m&&i>=dl;i--){
    ll t=1LL*a[i].t*b[m].p-1LL*a[i].p*b[m].t;
    if(t>g[m])g[m]=t,dm=i;
  }
  if(l<m)getg(l,m-1,dl,dm);
  if(r>m)getg(m+1,r,dm,dr);
}
int main(){
  scanf("%d",&n);
  for(i=1;i<=n;i++)scanf("%d%d",&a[i].t,&a[i].p);
  std::sort(a+1,a+n+1,cmp);
  for(i=1;i<=n;i++)b[i].t=b[i-1].t+a[i].t,b[i].p=b[i-1].p+a[i].p;
  getf(1,n-1,1,n),getg(1,n-1,1,n);
  for(i=1;i<n;i++)if(f[i]<g[i])q[++ans]=n-i;
  for(printf("%d\n",ans),i=ans;i;i--)printf("%d\n",q[i]);
  return 0;
}

  

时间: 2024-12-21 09:07:36

BZOJ1701 : [Usaco2007 Jan]Cow School牛学校的相关文章

[BZOJ1697][Usaco2007 Feb]Cow Sorting牛排序

1697: [Usaco2007 Feb]Cow Sorting牛排序 Time Limit: 5 Sec  Memory Limit: 64 MB Submit: 712  Solved: 416 [Submit][Status][Discuss] Description 农夫JOHN准备把他的 N(1 <= N <= 10,000)头牛排队以便于行动.因为脾气大的牛有可能会捣乱,JOHN想把牛按脾气的大小排序.每一头牛的脾气都是一个在1到100,000之间的整数并且没有两头牛的脾气值相同.

bzoj 1697: [Usaco2007 Feb]Cow Sorting牛排序

Description 农夫JOHN准备把他的 N(1 <= N <= 10,000)头牛排队以便于行动.因为脾气大的牛有可能会捣乱,JOHN想把牛按脾气的大小排序.每一头牛的脾气都是一个在1到100,000之间的整数并且没有两头牛的脾气值相同.在排序过程中,JOHN 可以交换任意两头牛的位置.因为脾气大的牛不好移动,JOHN需要X+Y秒来交换脾气值为X和Y的两头牛. 请帮JOHN计算把所有牛排好序的最短时间. Input 第1行: 一个数, N. 第2~N+1行: 每行一个数,第i+1行是第

bzoj1697:[Usaco2007 Feb]Cow Sorting牛排序 &amp; bzoj1119:[POI2009]SLO

思路:以bzoj1119为例,题目已经给出了置换,而每一次交换的代价是交换二者的权值之和,而置换一定是会产生一些环的,这样就可以只用环内某一个元素去置换而使得其余所有元素均在正确的位置上,显然要选择环内最小的数,但也可能存在一个数使得它不在当前处理的环内而它先与当前环内某个数进行交换,然后再在环内进行交换,再将之前那个数换回来,这样也显然要选择所有元素中最小的和当前环内最小的进行交换,然后取个min即可.然后还要注意可能当前环内最小的就是所有元素中最小的,特判一下即可. 1 #include<i

【BZOJ】1697: [Usaco2007 Feb]Cow Sorting牛排序

[算法]数学置换 [题意]给定n个数,要求通过若干次交换两个数的操作得到排序后的状态,每次交换代价为两数之和,求最小代价. [题解] 考虑置换的定义:置换就是把n个数做一个全排列. 从原数组到排序数组的映射就是经典的置换,这样的置换一定能分解成循环的乘积. 为什么任意置换都可以这样分解:原数组的每个数要交换到排序位置(有后继),每个数的原位置会有数字来替代(有前驱),故一定构成若干循环节. 循环节内要完成置换,需要按顺序依次替换位置进行len-1次对换(len为循环节长度). 对于每一循环节内部

P1697: [Usaco2007 Feb]Cow Sorting牛排序

这是一道置换群的裸题=-=,先拿来试试手对着打,以后应该会更加熟练吧! 1 const maxn=100001; 2 var n,i,j,maxx,minx,now,len,cursum,tmin,sum:longint; 3 p:array[0..maxn] of boolean; 4 agr,pos:array[0..maxn] of longint; 5 function min(a,b:longint):longint; 6 begin 7 if a>b then exit(b) 8 e

bzoj 1697: [Usaco2007 Feb]Cow Sorting牛排序【置换群】

至今都不知道置换群是个什么东西--题解说什么就是什么.jpg 以下来自hzwer:http://hzwer.com/3905.html #include<iostream> #include<cstdio> #include<algorithm> using namespace std; const int N=10005; int n,w[N],a[N],v[N]; struct qwe { int x,id; }b[N]; bool cmp(const qwe &a

[BZOJ1635][Usaco2007 Jan]Tallest Cow 最高的牛

1635: [Usaco2007 Jan]Tallest Cow 最高的牛 Time Limit: 5 Sec  Memory Limit: 64 MB Submit: 656  Solved: 402 [Submit][Status][Discuss] Description FJ's N (1 <= N <= 10,000) cows conveniently indexed 1..N are standing in a line. Each cow has a positive inte

1635: [Usaco2007 Jan]Tallest Cow 最高的牛

1635: [Usaco2007 Jan]Tallest Cow 最高的牛 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 383  Solved: 211[Submit][Status] Description FJ's N (1 <= N <= 10,000) cows conveniently indexed 1..N are standing in a line. Each cow has a positive integer height

BZOJ 1635: [Usaco2007 Jan]Tallest Cow 最高的牛

题目 1635: [Usaco2007 Jan]Tallest Cow 最高的牛 Time Limit: 5 Sec  Memory Limit: 64 MB Description FJ's N (1 <= N <= 10,000) cows conveniently indexed 1..N are standing in a line. Each cow has a positive integer height (which is a bit of secret). You are t