题解:P11085 [ROI 2019] 学生座位 (Day 2)
LastKismet · · 题解
Sol
首先是一个经典贪心。
考虑只有一个班,如何分组最优?显然排序后两两依次分组,这样同组内两人高度差最小,必然最优。
考虑多个班,同一张桌子必然有
那么我们就可以对各序号依次选择最合适的桌子。问题变成:给出一些点,一些区间,选择一个最合适的区间使得题目中给出的代价最小。
这时候我们发现这个问题是有决策单调性的。由于更大的组中各班的小组都比上一大组中相应的组大,不难想到这一组最合适的区间左端点不小于上一组。倘若左端点小于上一组,那么上一组选这个左端点更小的区间就会更优。这个多想一想就会发现特别显然。
因此我们就可以决策单调性简单解决这个问题了。
Code
int n,m,k;
struct desk{ll l,r;}ds[N];
map<ll,ll> mp;
ll h[N];
vec<ll> v[N];
vec<ll> sum[N];
ll ans;
inline void solve(int l,int r,int pl,int pr){
if(l>r)return;
int md=l+r>>1,pm;ll tans=INF;
rep(i,pl,pr){
int a=lower_bound(v[md].begin(),v[md].end(),ds[i].l)-v[md].begin()-1;
int b=upper_bound(v[md].begin(),v[md].end(),ds[i].r)-v[md].begin()-1;
ll t=a*ds[i].l-sum[md][a]+sum[md][m<<1]-sum[md][b]-(m*2-b)*ds[i].r;
if(t<tans){
tans=t;
pm=i;
}
}
ans+=tans;
solve(l,md-1,pl,pm);
solve(md+1,r,pm,pr);
}
inline void Main(){
read(m,n,k);
rep(i,1,k)read(ds[i].l,ds[i].r),chmax(mp[ds[i].l],ds[i].r);
int kk=0;
for(auto i:mp)ds[++kk]={i.fir,i.sec};
k=kk;
rep(i,1,m){
rep(j,1,n<<1)read(h[j]);
sort(h+1,h+1+(n<<1));
rep(j,1,n)v[j].pub(h[j*2-1]),v[j].pub(h[j*2]);
}
rep(i,1,n){
v[i].pub(0);
sort(v[i].begin(),v[i].end());
sum[i].resize(m<<1|1);
rep(j,1,m<<1)sum[i][j]=sum[i][j-1]+v[i][j];
}
solve(1,n,1,k);
put(ans);
}