CF1721C Min-Max Array Transformation(div.2)
题目链接
https://codeforces.com/problemset/problem/1721/C
题意简述
先给你一个非降序数组 \(a\) , 再创建两个数组 \(b\) 和 \(d\) ,我们令 $b_i =a_i+d_i $ ,然后再对数组 \(b\) 排序,并把排序后的数组 \(b\) 给你,请你找出在所有可能的数组 \(d\) 中 , \(d_i\) 的最小值和最大值 , 注意,每一个 \(d_i\)是相互独立的,这意味着每一个 \(d_i\) 可以来自于不同的数组 \(d\).
比如现在有两个数组 \(d\)
\(2\) \(4\) \(6\)
\(1\) \(7\) \(9\)
则得到的 \(d_i\) 的最小值数组与最大值数组分别为
\(1\,\,4\,\,6\)
\(2\,\,7\,\,9\)
样例
点击查看样例
算法标签
二分,贪心
分析
对于 \(d_i\) 的最小值,可以直接对数组 \(b\) 二分,找最小的大于等于 \(a_i\) 的.
对于 \(d_i\) 的最大值,如果是从前往后计算:我们应该先处理\(a[i+1]\sim a[n]\),显然,只需要从\(a[i+1]\) 开始,删除数组 \(b\) 中最小的大于等于 \(a[i+1]\) 的元素(这是 \(a[j]\) 能满足 \(d[j]\) 非负这个条件的最低要求),剩下的元素中的最大值就是 \(a[i]\) 对应的 \(d[i]\) .从前往后的话每一次都要复制一遍 $ b$ 数组然后删除元素,而从后往前取完最大值后可以直接删除最小的大于等于 \(a[j]\) 的 ,所以从后往前会更方便.
如果理解了为什么要从后往前可以忽略下面这段.
应该从后往前计算,因为要优先满足大的元素的要求,否则你当前的 \(a_i\) 先把大的位置占了,后面大的值就没有对应的 \(b_i\)了.然后每一次取当前 \(b_i\) 的最大值,并删掉最小的大于等于 \(a_i\) 的元素(这是 \(a_i\) 能有解的最低要求,不要直接删除 \(b_i\) 中最大的元素,因为前面的元素可能还能用到 )
multiset
是可以有重复元素的集合,刚开始不知道,就用了 map
,导致代码写的很长
一部分hack样例
\(Sample\) \(Input\)
1
3
10 20 30 30
10 22 40 50
\(Sample\) \(Output\)
0 2 10 10
0 12 20 20
代码
点击查看代码
#include<stdio.h>
#include<iostream>
#include<cstdlib>
#include<string.h>
#include<algorithm>
#include<set>
using namespace std;
const int N=2e5+10;
int a[N];
int b[N];
int d[N];
multiset<int> s;
int main()
{
//freopen("uva.txt","r",stdin);
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
{
scanf("%d",&b[i]);
s.insert(b[i]);//把b数组的元素存入multiset中,可以快速地查找和删除元素.时间复杂度O(logn)
}
for(int i=1;i<=n;i++)
{
int pos=lower_bound(b+1,b+n+1,a[i])-b;
if(pos<=n)
{
d[i]=b[pos]-a[i];
}
}
for(int i=1;i<=n;i++)
{
printf("%d ",d[i]);
}
printf("\n");
for(int i=n;i>=1;i--)
{
d[i]=*(--s.end())-a[i];// *(--s.end())意为取b中的未被删除的最大的元素
//auto t=lower_bound(s.begin(),s.end(),a[i]);
//s.erase(t);//删掉最小的大于等于a[i]的元素
/*按上面的写法交上去TLE了,下面的写法AC.经询问大佬得知,lower_bound在用于set,map这种(底层是红黑树实现的)结构时复杂度是O(n),所以最好用他自带的,复杂度为O(logn)*/
s.erase(s.lower_bound(a[i]));
}
for(int i=1;i<=n;i++)
{
printf("%d ",d[i]);
}
printf("\n");
}
return 0;
}