天天看點

Food Stalls (2019 Google Kickstart Round D)

題目連結:https://codingcompetitions.withgoogle.com/kickstart/round/0000000000051061

我。。。。這還能不按照x順序給出的嗎。。。,前兩個樣例都是順序給出的,第三個樣例我沒注意。。。但怎麼過了第三個樣例啊。。。難頂,分低了還罰時爆炸

我們假設目前選出了k+1個位置,那麼這k+1個位置的c是固定加到代價裡去的,那麼這個時候貨物倉庫肯定放在中間最好,我之前糾結了一個問題就是加入中間位置有兩個地方,那麼到底放在哪個,後來發現中間位置有兩個的時候放在左邊還是右邊,距離差都是一樣的。

是以我們k1=k/2,k2=k-k1,從左向右枚舉食品倉庫,然後左邊每個地方的值變成 a[i]c-a[i].x,右邊每個地方的權值變成a[i].c+a[i].x。

那麼目前食品倉庫放在 i 号位置,所能得到的最小代價tmp=左邊最小k1個值+右邊最小的k2個值+k1*a[i]-k2*a[i]。

左邊最小k1個值用一個堆維護,右邊最小k2個值用一個堆表示沒進入最小k2個的值和下标,再用一個set表示哪些下标在最小的k2個中。每次枚舉食品倉庫的位置i+1,就隻要兩邊都維護一次,logn複雜度,總複雜度就是nlogn

#include<bits/stdc++.h>
#define maxl 300010

using namespace std;

int n,k,m,cas;
struct node
{
	int x,c;
}a[maxl];
typedef pair<int,int> p;
priority_queue<int> q1;
set <int> s;
priority_queue<p,vector<p>,greater<p> > q2;
long long ans;

inline bool cmp(const node &x,const node &y)
{
	return x.x<y.x;
}

inline void prework()
{
	scanf("%d%d",&k,&n);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i].x);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i].c);
	sort(a+1,a+1+n,cmp);
} 

inline void mainwork()
{
	while(!q1.empty()) q1.pop();
	while(!q2.empty()) q2.pop();
	s.clear();
	int k1=k/2,k2=k-k1;
	long long tmp=a[k1+1].c;p d;
	for(int i=1;i<=k1;i++)
	{
		q1.push(a[i].c-a[i].x);
		tmp+=-a[i].x+a[i].c; 
	}
	for(int i=n;i>=k1+2;i--)
		q2.push(make_pair(a[i].c+a[i].x,i));
	for(int i=1;i<=k2;i++)
	{
		d=q2.top();q2.pop();
		tmp+=d.first;
		s.insert(d.second);
	}
	ans=tmp+1ll*k1*a[k1+1].x-1ll*k2*a[k1+1].x;
	for(int i=k1+2;i<=n-k2;i++)
	{
		tmp-=a[i-1].c;tmp+=a[i].c;
		if(!q1.empty())
		if(a[i-1].c-a[i-1].x<q1.top())
		{
			tmp-=q1.top();q1.pop();
			tmp+=a[i-1].c-a[i-1].x;
			q1.push(a[i-1].c-a[i-1].x);
		}
		if(s.begin()!=s.end())
		if((*s.begin())==i)
		{
			tmp-=a[i].c+a[i].x;
			s.erase(s.begin()); 
			do
			{
				d=q2.top();q2.pop();
			}while(d.second<=i);
			tmp+=d.first;
			s.insert(d.second);
		}
		ans=min(ans,tmp+1ll*k1*a[i].x-1ll*k2*a[i].x);
	}
}

inline void print()
{
	printf("Case #%d: ",cas);
	printf("%lld\n",ans);
}

int main()
{
	int t;
	scanf("%d",&t);
	for(cas=1;cas<=t;cas++)
	{ 
		prework();
		mainwork();
		print();
	}
	return 0;
}