专栏文章

题解:P7990 [USACO21DEC] Closest Cow Wins S

P7990题解参与者 6已保存评论 8

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
8 条
当前快照
1 份
快照标识符
@mioj2hdj
此快照首次捕获于
2025/12/02 20:01
3 个月前
此快照最后确认于
2025/12/02 20:01
3 个月前
查看原文

思路

这是一道贪心题,需要计算子区间的最大收益。
在两头对方的牛之间,可以最多放 22 头牛。因为再多就不必要了。
  • 不放牛:这两头对方的牛之间的草地不要。
  • 11 头牛:情况较为复杂,设左右对方的牛坐标为 llrr ,我方牛坐标为 kk ,则 (l+k2,r+k2)(\frac{l+k}{2},\frac{r+k}{2}) 中的草地归我方所有,注意距离双方相同的草地归属对方
  • 22 头牛: 这两头对方的牛之间的草地全要。
此时会产生一个小问题,第 11 头对方的牛之前的草地和第 mm 头对方的牛之后的草地无法维护,所以需要在代码实现上添加第 00 头牛和第 m+1m+1 头牛分别在坐标 inf-\infinf\inf ,或直接特殊处理,以确保它们不会影响我方牛占领草地的情况。

代码实现

我们可以用一个滑动窗口来维护整个区间的收益,从左到右枚举一头牛的收益并取最大值,详见代码。
CPP
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e5+10;
int k,m,n,f[N];
int p,en=2,e=2,g[N],q[N];
struct node{
	int p,t;
	bool operator<(const node&b)const{
		return p<b.p;
	}
}a[N];
signed main()
{
	cin>>k>>m>>n;
	for(int i=0;i<k;i++) cin>>a[i].p>>a[i].t;
	for(int i=1;i<=m;i++) cin>>f[i];
	sort(a,a+k); 
	sort(f+1,f+m+1); //该题不保证输入升序,所以要排序 
	while(p<k&&a[p].p<f[1]) g[0]+=a[p++].t; // 特判第一头牛 
	for(int i=1;i<m;i++)
	{
		int l=p,hh=0,tt=0,ans=0,t=0,mx=0;
		while(p<k&&a[p].p<=f[i+1]) p++;
		for(int j=l;j<p;j++)
		{
			q[hh++]=j;
			ans+=a[j].t;
			t+=a[j].t;
			while(hh!=tt&&(a[j].p-a[q[tt]].p)*2>=f[i+1]-f[i]) ans-=a[q[tt++]].t;
			mx=max(ans,mx); //取各个窗口收益的最大值
		}
		g[e++]=mx;
		g[e++]=t-mx; //存储可能的答案收益 
	}
	while(p<k) g[e]+=a[p++].t; //特判最后的牛 
	e++;
	sort(g,g+e);
	int ans=0;
	for(int i=1;i<=n;i++) ans+=g[--e]; //接收最大的 n 份收益 
	cout<<ans;
	return 0;
}

评论

8 条评论,欢迎与作者交流。

正在加载评论...