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);
不写了眼睛好累

浙公网安备 33010602011771号