P5574 [CmdOI2019] 任务分配问题的一个更优做法
forest114514 · · 题解
首先大家都知道了
但是在阅读完 APIO2021 Itst 大神的课件之后我们有一种可以由冷门科技 Wilber 算法改造的小清新做法。(其实就是把 SMAWK 换成了小清新决策单调性分治)
具体地,首先用
放一下本题这个部分的代码 (是不是非常小清新):
void divide(int l,int r,int L,int R,const int &_mid){//决策单调性分治
if(l>r) return;
int mid=l+r>>1,p=L;
F[mid]=(NODE){G[L].val+w(L+1,mid)+_mid,G[L].ch+1};
rep(i,L+1,min(mid-1,R)){
delL(cl++);//卡常
NODE tmp=(NODE){G[i].val+val+_mid,G[i].ch+1};
if(tmp<F[mid]) F[mid]=tmp,p=i;
}
divide(l,mid-1,L,p,_mid);
divide(mid+1,r,p,R,_mid);
}
int Wilber(int mid){
int r=0,c=0;
cl=1,cr=0,TR.tt=0,memset(TR.c,0,sizeof TR.c);
while(r<n){
int ri=min(n,r+r-c+1);
F=g,G=f,divide(r+1,ri,c,r,mid);//第一部分:用f估计得到g
F=h,G=g,divide(r+2,ri,r+1,ri,mid);//第二部分:用g估计得到h
int t=r+2;f[r+1]=g[r+1];
while(t<=ri&&g[t]<h[t]) f[t]=g[t],++t;//找到第一个h比j优的t
if(t>ri) r=ri;//t不存在,[c,r]->[c,ri]
else f[t]=h[t],c=r+1,r=t;//t存在,[c,r]->[r+1,t]
}
return f[n].ch;
}
注意到花费了
然后就直接套上 wqs 二分,时间复杂度
提一句这里可以用序列分块套值域分块做到
code(注意值域上界不是
const int N=25500;
int n,k,a[N];
struct BIT{
int c[N],tt;
#define lowbit(x) (x&(-x))
void update(int u,int x){tt+=x;for(;u<=n;u+=lowbit(u)) c[u]+=x;}
int query(int u){int res=0;for(;u;u-=lowbit(u)) res+=c[u];return res;}
}TR;
int cl,cr;
LL val;
void delR(int i){val-=TR.query(a[i]-1),TR.update(a[i],-1);}
void addR(int i){val+=TR.query(a[i]-1),TR.update(a[i],1);}
void delL(int i){val-=TR.tt-TR.query(a[i]),TR.update(a[i],-1);}
void addL(int i){val+=TR.tt-TR.query(a[i]),TR.update(a[i],1);}
LL w(int l,int r){
while(cr>r) delR(cr--);
while(cl<l) delL(cl++);
while(cr<r) addR(++cr);
while(cl>l) addL(--cl);
return val;
}
struct NODE{
LL val;int ch;
bool operator <(const NODE &T)const{
return val==T.val?ch>T.ch:val<T.val;
}
}f[N],g[N],h[N],*F,*G;
void divide(int l,int r,int L,int R,const int &_mid){
if(l>r) return;
int mid=l+r>>1,p=L;
F[mid]=(NODE){G[L].val+w(L+1,mid)+_mid,G[L].ch+1};
rep(i,L+1,min(mid-1,R)){
delL(cl++);
NODE tmp=(NODE){G[i].val+val+_mid,G[i].ch+1};
if(tmp<F[mid]) F[mid]=tmp,p=i;
}
divide(l,mid-1,L,p,_mid);
divide(mid+1,r,p,R,_mid);
}
int Wilber(int mid){
int r=0,c=0;
cl=1,cr=0,TR.tt=0,memset(TR.c,0,sizeof TR.c);
while(r<n){
int ri=min(n,r+r-c+1);
F=g,G=f,divide(r+1,ri,c,r,mid);
F=h,G=g,divide(r+2,ri,r+1,ri,mid);
int t=r+2;f[r+1]=g[r+1];
while(t<=ri&&g[t]<h[t]) f[t]=g[t],++t;
if(t>ri) r=ri;
else f[t]=h[t],c=r+1,r=t;
}
return f[n].ch;
}
LL wqs(){
int l=0,r=1e8,ans;
while(l<=r){
int mid=l+r>>1;
if(Wilber(mid)>=k) ans=mid,l=mid+1;
else r=mid-1;
}
Wilber(ans);
return f[n].val-1ll*ans*k;
}