hdu 3884 Hinanai Tenshi’s peach garden
http://acm.hdu.edu.cn/showproblem.php?pid=3884
二分+验证
验证是否可以把t个桃子放在同一点的时候,
这t个桃子必然是连续的,假设存在于区间[a,b]
这个区间的两个端点必然有一个是满的(所以扫描的时候左右扫两遍)
先假设a点是满的
那么找第t个桃子所在的位置
再找中间第(t+1)/2 个桃子的位置 (距离和最小)
此时得到中间位置,左右两边的位置,就可以验证是否超出花费了。
注:当t是偶数的时候,中间的桃子应该是有两个的,我考虑之后就TLE了,因为我的算法复杂度是 O(lgm*n*lgn*lgn) (m是桃子总数,n是位置数)
后来统一考虑中间的那个桃子就是第(t+1)/2个,就900多ms过了==!
#include <iostream> #include <cstdio> #include <algorithm> #include <string.h> #include <cmath> #include <vector> using namespace std; __int64 N,K; const int maxn = 10005; struct node { __int64 x; __int64 p; }a[maxn]; __int64 lb[maxn]; __int64 lc[maxn]; __int64 rb[maxn]; __int64 rc[maxn]; void solve() { lb[0]=0,lc[0]=0; for(int i=1;i<=N;i++) { lb[i]=lb[i-1]+a[i].p; lc[i]=lc[i-1]+a[i].p*a[i].x; } rb[N+1]=0,rc[N+1]=0; for(int i=N;i>=1;i--) { rb[i]=rb[i+1]+a[i].p; rc[i]=rc[i+1]+a[i].p*a[i].x; } } int Find_left(int pur,int l,int r,__int64 v) { int ans=N+1; while(l<=r) { int mid=(l+r)/2; if(lb[mid]-lb[pur-1]==v) return mid; else if(lb[mid]-lb[pur-1]<v) l=mid+1; else { if(mid<ans) ans=mid; r=mid-1; } } if(ans==N+1) return -1; return ans; } int Find_right(int pur,int l,int r,__int64 v) { int ans=0; while(l<=r) { int mid=(l+r)/2; if(rb[mid]-rb[pur+1]==v) return mid; else if(rb[mid]-rb[pur+1]<v) r=mid-1; else { if(mid>ans) ans=mid; l=mid+1; } } if(ans==0) return -1; return ans; } bool Is_true(__int64 t) //验证是否可以放t个桃子到同一个点 { int l=0,r=0,mid=0; __int64 suk=0; for(int i=1;i<=N;i++) { suk=0; l=i; r=Find_left(i,i,N,t); if(r==-1) continue; mid=Find_left(i,i,N,(t+1)/2); suk+=a[mid].x*(lb[mid-1]-lb[l-1])-(lc[mid-1]-lc[l-1]); suk+=lc[r-1]-lc[mid]-a[mid].x*(lb[r-1]-lb[mid]); suk+= (a[r].p-(lb[r]-lb[l-1]-t))*(a[r].x-a[mid].x); if(suk<=K) return true; /* if(t%2==0) { suk=0; mid=Find_left(i,i,N,(t+2)/2); suk+=a[mid].x*(lb[mid-1]-lb[l-1])-(lc[mid-1]-lc[l-1]); suk+=lc[r-1]-lc[mid]-a[mid].x*(lb[r-1]-lb[mid]); suk+= (a[r].p-(lb[r]-lb[l-1]-t))*(a[r].x-a[mid].x); if(suk<=K) return true; }*/ } for(int i=N;i>=1;i--) { suk=0; r=i; l=Find_right(i,1,i,t); if(l==-1) continue; mid=Find_right(i,1,i,(t+1)/2); suk+=rc[mid+1]-rc[i+1]-a[mid].x*(rb[mid+1]-rb[i+1]); suk+=a[mid].x*(rb[l+1]-rb[mid])-(rc[l+1]-rc[mid]); suk+=(a[l].p-(rb[l]-rb[r+1]-t))*(a[mid].x-a[l].x); if(suk<=K) return true; /* if(t%2==0) { suk=0; mid=Find_right(i,1,i,(t+2)/2); suk+=rc[mid+1]-rc[i+1]-a[mid].x*(rb[mid+1]-rb[i+1]); suk+=a[mid].x*(rb[l+1]-rb[mid])-(rc[l+1]-rc[mid]); suk+=(a[l].p-(rb[l]-rb[r+1]-t))*(a[mid].x-a[l].x); if(suk<=K) return true; }*/ } return false; } int cmp(node a1,node a2) { return a1.x<a2.x; } int main() { __int64 sum=0; while(scanf("%I64d %I64d",&N,&K)!=EOF) { sum=0; for(int i=1;i<=N;i++) { scanf("%I64d %I64d",&a[i].x,&a[i].p); sum+=a[i].p; } sort(a+1,a+N+1,cmp); solve(); __int64 l=0; __int64 r=sum; __int64 ans=0; while(l<=r) { __int64 mid=(l+r)/2; if(Is_true(mid)==true) { if(ans<mid) ans=mid; l=mid+1; } else r=mid-1; } printf("%I64d\n",ans); } return 0; }