[ROI 2019 Day2]课桌
Posted StaroForgin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[ROI 2019 Day2]课桌相关的知识,希望对你有一定的参考价值。
课桌
题解
首先,我们可以观察到结论,在同一组内,我们按高度排序后,
a
2
i
−
1
a_{2i-1}
a2i−1肯定会与
a
2
i
a_{2i}
a2i坐在同一张桌子上。
应该是很好感性理解的,因为这样可以让我们匹配的两张桌子的差值最小,我们不可能找出一种更优的匹配方案。画下图就知道了
由于我们总共只能选择
n
n
n张桌子,所以肯定是较小的对坐较小的桌子,较大的对坐较大的桌子。
我们该如何比较两张桌子的大小呢,由于对于区间
[
L
j
,
R
j
]
⊂
[
L
i
,
R
i
]
[L_{j},R_{j}]\\subset[L_{i},R_{i}]
[Lj,Rj]⊂[Li,Ri],当选择区间
j
j
j时我们都能用区间
i
i
i代替,而且区间
i
i
i永远优于区间
j
j
j,所以这样被包含的区间
j
j
j我们是永远都不会选的。
于是,可以发现,我们所选择的区间
i
,
j
i,j
i,j应该满足
L
i
<
L
j
⩽
R
i
<
R
j
L_{i}<L_{j}\\leqslant R_{i}<R_{j}
Li<Lj⩽Ri<Rj的性质。
这样,对于每组选择好了的桌子的情况,每对人所坐的桌子也是固定的。
不同组的
a
2
i
−
1
a_{2i-1}
a2i−1与
a
2
i
a_{2i}
a2i肯定都坐的是同一张桌子,所以我们可以把这些人提取出来,对他们单独找出最优的一张桌子。
找桌子的过程我们可以将所有的桌子排序后用双指针进行维护,时间复杂度是
O
(
n
(
m
+
k
)
)
O\\left(n(m+k)\\right)
O(n(m+k))。的,显然是过不了的。
但我们可以考虑我们上面的性质:较小的对坐较小的桌子,较大的对坐较大的桌子,也就是我们选择的桌子是单调的。
于是,我们可以考虑通过二分来对其维护。
每次二分区间对
(
[
l
,
r
]
,
[
a
l
,
a
r
]
)
([l,r],[al,ar])
([l,r],[al,ar])表示区间
[
l
,
r
]
[l,r]
[l,r]中的配对应该在区间
[
a
l
,
a
r
]
[al,ar]
[al,ar]中找到自己所匹配的桌子,如果我们的第
m
i
d
mid
mid对匹配的桌子
k
k
k,那么我们就应该下传到区间对
(
[
l
,
m
i
d
−
1
]
,
[
a
l
,
k
]
)
([l,mid-1],[al,k])
([l,mid−1],[al,k])与区间对
(
[
m
i
d
+
1
,
r
]
,
[
a
r
,
k
]
)
([mid+1,r],[ar,k])
([mid+1,r],[ar,k])中。
显然,它后面的不可能选比它还低的桌子,它前面的也不可能选比它还高的桌子,所以我们显然是可以这样二分的。
总共有
l
o
g
log
log层,而每层会覆盖区间
[
1
,
k
]
[1,k]
[1,k]一次,这显然是
log
n
\\log\\,n
logn级别的。
将所有桌子排完序后跑一遍就可以了。
时间复杂度 O ( n m + ( m + k ) log n ) O\\left(nm+(m+k)\\log\\,n\\right) O(nm+(m+k)logn)。
源码
#include<bits/stdc++.h>
using namespace std;
#define MAXN 200005
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
typedef long long LL;
const LL INF=0x3f3f3f3f3f3f3f3f;
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
template<typename _T>
void print(_T x){if(x>9)print(x/10);putchar(x%10+'0');}
int n,m,k,cnt,tmp[MAXN<<1],tot;LL ans;
struct ming{int l,r;}s[MAXN],d[MAXN];
vector<int>vec[MAXN];
bool cmp(ming x,ming y){
if(x.l==y.l)return x.r>y.r;
return x.l<y.l;
}
int check(int ai,int al,int ar){
for(int i=1;i<=m;i++)
tmp[++tot]=vec[i][ai+ai],
tmp[++tot]=vec[i][ai+ai+1];
sort(tmp+1,tmp+tot+1);
int jl=0,jr=0,rk;LL res=INF,suml=0,sumr=0,summ=0;
for(int i=1;i<=tot;i++)summ+=tmp[i];
for(int i=al;i<=ar;i++){
while(jl<tot&&tmp[jl+1]<=d[i].l)jl++,suml+=tmp[jl];
while(jr<tot&&tmp[jr+1]<=d[i].r)jr++,sumr+=tmp[jr];
LL tmp=1ll*jl*d[i].l-suml+summ-sumr-1ll*(tot-jr)*d[i].r;
if(tmp<res)res=tmp,rk=i;
}
ans+=res;tot=0;return rk;
}
void sakura(int l,int r,int al,int ar){
int mid=l+r>>1,mi=check(mid,al,ar);
if(l<mid)sakura(l,mid-1,al,mi);
if(r>mid)sakura(mid+1,r,mi,ar);
}
int main(){
read(m);read(n);read(k);
for(int i=1,l,r;i<=k;i++)
read(l),read(r),s[i]=(ming){l,r};
for(int i=1,x;i<=m;i++)
for(int j=1;j<=n+n;j++)
read(x),vec[i].pb(x);
for(int i=1;i<=m;i++)sort(vec[i].begin(),vec[i].end());
sort(s+1,s+k+1,cmp);int lst=0;cnt=0;
for(int i=1;i<=k;i++)if(s[i].r>lst)
d[++cnt]=s[i],lst=s[i].r;
sakura(0,n-1,1,cnt);
printf("%lld\\n",ans);
return 0;
}
谢谢!!!
以上是关于[ROI 2019 Day2]课桌的主要内容,如果未能解决你的问题,请参考以下文章