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;
}

posted on 2011-08-03 02:08  lwbaptx  阅读(342)  评论(0编辑  收藏  举报

导航