CodeForces-Heavy Intervals

题目

题目思路

我以为总长度不变的情况下 怎么换都没关系,所以只需要让Cmax...Cmin*每个区间短-长即可,事实上不行,

虽然[2,5]与[3,8] 100 1与[2,8],[3,5] 100 1 就不一样,所得答案也不同,但是你可以注意到这两个交换了答案确实最优解,这其实就是这题的规律。

就是 左端点不断匹配最近的右端点,形成包含的关系。

怎么证明呢,跟前面我写的一道博弈论题目一样的

题目

怎么证明呢 ?

假设有 a<c<b<d  b-a<d-c
[a,b] [c,d] c: x <y
交换
[c,b] [a,d] c不变
前者最优贡献:
(b-a)*y+(d-c)*x
如果说  应该交换 形成 [a,d],[c,b]
按道理后者的贡献要更小 即前式>后式
由于b+a<d+c 所以d-a>b-c
  所以后式 
  (b-c)*y+(d-a)*x
  两者比较会发现
  by-ay+dx-cx?by-cy+dx-ax
  -ay+cy?cx-ax
  y(c-a)?x(c-a)所以
  ?为> 发现前式更大 所以应该交换 
                  

然后就是我在这个过程中,开始把这种交叉数据变成包含的关系就行了,这个过程会有点麻烦,我看了别的人用双指针去写就是这样的

这个注意实现起来麻烦,逻辑不难的
说实话 我都不会 我后面看到了博主用优先队列实现,我就学过来了。详见代码

#include<iostream>
#include<cstring>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;
int n;
int l[100005];
int r[100005];
int c[100005];
int g[100005];
long long ans;
bool cmp(int a,int b)
{return a>b;}
void solve()
{
   cin>>n;
	//又是cin 又是read 会出错
//	memset(l,0,sizeof l);
//	memset(r,0,sizeof r);
//	memset(c,0,sizeof c);//这个很耗时
	ans=0;
	priority_queue<ll>q;
	vector<ll>v;
	for(int i=1;i<=n;i++)cin>>l[i];
	for(int i=1;i<=n;i++)cin>>r[i];
	for(int i=1;i<=n;i++)cin>>c[i];
	sort(l+1,l+1+n);
	sort(r+1,r+1+n);
	sort(c+1,c+1+n);
	int i=1;
	for(int j=1;j<=n;j++)
	{
		while(i<=n&&r[j]>l[i]) //3 8   12 23
		{
			q.push(l[i]);
			i++;
		}
		v.push_back(r[j]-q.top());
	//	cout<<r[j]-q.top()<<endl;
        q.pop();
	}
	vector<ll>::iterator it=v.begin();
//不能q.clear,多的那些后面人直接吃进去o
	sort(v.begin(),v.end(),cmp);
//	while(it!=v.end())
//	{
//		cout<<*it;
//		it++;
//		cout<<endl;
//	}
	for(int i=0;i<n;i++)
	{
		ans+=v[i]*c[i+1];
		//为什么那样子就很慢呢???啊
		//
     //   ans+=v.front()*c[i];
	//	v.erase(v.begin());
	}
	cout<<ans<<endl;
		return ;
}
int main()
{
   int t;
	cin>>t;

	cin.tie(0);
	cout.tie(0);

	while(t--)
		solve();
	
	
	return 0;

}

代码想讲下,

首先是memset 时间复杂度是\(\mathcal{O(n^2)}\),

我一开始ans+不是那样写的这个后面讲,然而他#2 t了 我上网查了下初始化数组然后数据大的话时间会耗点,

然后我就想算了不初始化了反正没事,然后神奇的2没有t了,

那两个代码时间复杂度其实是一样的,但是操作上却又点影响,不过那是代码不是正解的问题。而且卡的也很严


第二个想讲的 就是这个erase操作,千万别放for循环里真的数据大了会超时的,每一次erase操作\(\mathcal{O(n)}\),for n次 相当于n^2,肯定超时的,于是就换了,我老是忘记用v[i]直接表示


讲下vector的sort排序是这样的

std::sort(v.begin(), v.end(), std::greater<int>());
后面那个表示从大到小 可以去掉std::,也可以自己写个cmp

然后q.pop是\(\mathcal{O(1)}\)

最后补充个fil初始化 跟memset相比最大的好处 可以初始化任意值

 std::fill(array, array + size, 10);

不写了眼睛好累

posted @ 2025-04-16 20:25  LteShuai  阅读(20)  评论(0)    收藏  举报