其他分享
首页 > 其他分享> > 【做题记录】CF746F Music in Car

【做题记录】CF746F Music in Car

作者:互联网

Problem

CF746F

题目大意:

有 \(k\) 的时间,\(n\) 首歌,听每首歌的时间不一定相同,要求按顺序听一段连续的歌,其中有 \(w\) 首可以只听一半(向上取整)。每首歌有一个快乐值,听第 \(i\) 首歌即可获得 \(a_i\) 的快乐值(不论听整首还是半首),问能获得的最大的快乐值是多少。

Solution

首先有一个很明显的事,就是对于每一个确定的区间左边界 \(l\),一定要使 \(r\) 尽可能的大,也就是确定做断电后,只要能扩展区间就扩展区间。然后看数据范围,\(1\le n \le 2 \times 10^5\),可以想到要用 \(O(n\log n)\) 或者 \(O(n)\) 的算法。
于是我们考虑用 two-pointers 解决这题。
这时还需要用到一个贪心,就是对于目前 two-pointers 找到的一个区间 \([l,r]\),我们必然让时间最大的 \(w\) 首歌只听一半。

具体实现时,我们可以用 STL 中的 multiset<> 来存储歌曲,这里不能用 set<> 是因为两首歌的时间可能一样。
我们用两个 multiset<> \(s_1,s_2\) 分别存储听一半的歌的原本的时间和听整首歌的时间。
对于每次将要进入区间的一个数,我们进行分类讨论:

于是就可以完成此题了!

Code

#include<bits/stdc++.h>
using namespace std;
int n,w,k,a[200005],t[200005];
int T,res,ans;
multiset<int>s1,s2;
int main()
{
	scanf("%d%d%d",&n,&w,&k);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=1;i<=n;i++) scanf("%d",&t[i]);
	int l=1,r=0;
	while(r<n)
	{
		r++;
		int tmp=*s1.begin();
		if((int)s1.size()<w&&T+(t[r]+1)/2<=k)
			s1.insert(t[r]),T+=(t[r]+1)/2,res+=a[r];
		else if(t[r]>tmp&&T-(tmp+1)/2+(t[r]+1)/2+tmp<=k)
		{
			s1.erase(s1.find(tmp));
			s1.insert(t[r]);
			s2.insert(tmp);
			T+=(t[r]+1)/2-(tmp+1)/2+tmp;
			res+=a[r];
		}
		else if(T+t[r]<=k) s2.insert(t[r]),T+=t[r],res+=a[r];
		else
		{
			r--;
			if(s1.empty()){r++;continue;}
			else if(s2.empty()) s1.erase(s1.find(t[l])),T-=(t[l]+1)/2;
			else if(t[l]<tmp) s2.erase(s2.find(t[l])),T-=t[l];
			else
			{
				int ttmp=*--s2.end();
				s1.erase(s1.find(t[l]));
				s1.insert(ttmp);
				s2.erase(s2.find(ttmp));
				T=T-(t[l]+1)/2-ttmp+(ttmp+1)/2;
			}
			res-=a[l];
			l++;
		}
		ans=max(ans,res);
	}
	printf("%d\n",ans);
	return 0;
}

标签:CF746F,Car,首歌,int,时间,端点,区间,Music,放入
来源: https://www.cnblogs.com/mk-oi/p/14990076.html