【JZOJ100005】【NOI2017模拟.4.1】Shoes

来源:互联网 发布:rt809f编程器 自制 编辑:程序博客网 时间:2024/06/06 00:28

任务

这里写图片描述
这里写图片描述

解法

我们考虑将每双鞋按两鞋的中点排序,然后把鞋子放的就是一段连续的区间了。
现在我们设f[i][j]表示前i双鞋子,用了j个鞋柜,所需要的最小代价,就有

fi,j=mink<i{fk,j1+w(k+1,i)}

其中w(k+1,i)表示把第k+1i双鞋放在一个鞋柜中的最小代价。
显然我们要求w(k+1,i)的话,就要知道第k+1i双鞋的分布情况,这个可以用主席树来维护。
知道了分布情况之后,我们再主席树中,找出中位数位置;
知道鞋柜位置之后,然后我们就再利用主席数,统计每只鞋子到这个位置的距离和。
这样的时间复杂度为O(n2klog)


如果我们先枚举j,再枚举i,我们发现fi,j的决策点k不会小于fi,j的决策点k,其中i<i
那么我们就可以利用决策单调性来维护。
我这里采用的是分治法:
先算出fmid,i的决策点kmid,那么对于左右区间而言,枚举的决策点就可以减少了。


总的时间复杂度为O(nklog2)

代码

#include<iostream>#include<algorithm>#include<math.h>#include<stdio.h>#include<string.h>#define ll long long#define fo(i,x,y) for(ll i=x;i<=y;i++)#define f(x,y) f[(x)*(m+1)+(y)]using namespace std;const char* fin="shoes.in";const char* fout="shoes.out";const ll inf=0x7fffffff;const ll maxn=200007,maxt=maxn*60;ll n,m,f[maxn],num,last,rt[maxn],ans,lim;struct shoes{    ll x,y;}a[maxn];bool cmp(shoes a,shoes b){return (a.x+a.y)/2.0<(b.x+b.y)/2.0;}struct node{    ll x,l,r,lson,rson;}c[maxt];void modify(ll l,ll r,ll t,ll v,ll _t){    ll mid=(l+r)/2;    if (l==r){        c[t].x=c[_t].x+1;        return;    }    if (v<=mid){        c[t].rson=c[_t].rson;        modify(l,mid,c[t].lson=++num,v,c[_t].lson);    }else{        c[t].lson=c[_t].lson;        modify(mid+1,r,c[t].rson=++num,v,c[_t].rson);    }    c[t].x=c[c[t].lson].x+c[c[t].rson].x;    c[t].l=c[c[t].rson].l+c[c[t].lson].l+c[c[t].rson].x*(mid-l+1);    c[t].r=c[c[t].lson].r+c[c[t].rson].r+c[c[t].lson].x*(r-mid);}ll query(ll l,ll r,ll t,ll v,ll _t){    ll mid=(l+r)/2;    if (r<=v) return c[t].r-c[_t].r+(c[t].x-c[_t].x)*(v-r);    if (l>=v) return c[t].l-c[_t].l+(c[t].x-c[_t].x)*(l-v);    return query(l,mid,c[t].lson,v,c[_t].lson)+query(mid+1,r,c[t].rson,v,c[_t].rson);}ll getmid(ll l,ll r,ll t,ll _t,ll ls,ll rs){    ll mid=(l+r)/2,L=c[c[t].lson].x-c[c[_t].lson].x+ls,R=c[c[t].rson].x-c[c[_t].rson].x+rs;    if (l==r) return l;    if (L<R) return getmid(mid+1,r,c[t].rson,c[_t].rson,L,rs);    else if (L>R) return getmid(l,mid,c[t].lson,c[_t].lson,ls,R);    else return mid;}ll mincost(ll l,ll r){return query(1,2e9+1,rt[r],getmid(1,2e9+1,rt[r],rt[l],0,0),rt[l]);}void dfs(ll j,ll l,ll r,ll L,ll R){    ll mid=(l+r)/2,tmd=0;    if (l>r) return;    fo(k,L,min(mid-1,R)){        if (f(k,j-1)<lim){            ll tmp=f(k,j-1)+mincost(k,mid);            if (tmp<f(mid,j)){                f(mid,j)=tmp;                tmd=k;            }            if (n==mid) ans=min(f(mid,j),ans);        }    }    dfs(j,l,mid-1,L,tmd);    dfs(j,mid+1,r,tmd,R);}int main(){    freopen(fin,"r",stdin);    freopen(fout,"w",stdout);    scanf("%lld%lld",&n,&m);    fo(i,1,n){        scanf("%lld%lld",&a[i].x,&a[i].y);        a[i].x+=1e9+1;        a[i].y+=1e9+1;    }    sort(a+1,a+n+1,cmp);    memset(f,127,sizeof(f));    lim=f[0];    ans=f[0];    f(0,0)=0;    rt[0]=0;    fo(i,1,n){        modify(1,2e9+1,rt[i]=++num,a[i].x,rt[i-1]);        modify(1,2e9+1,rt[i],a[i].y,rt[i]);    }    fo(j,1,m)        dfs(j,1,n,0,n);    printf("%lld",ans);    return 0;}
0 0
原创粉丝点击