首页 > 其他 > 详细

BZOJ5125: [Lydsy1712月赛]小Q的书架(DP决策单调性)

时间:2018-11-15 15:02:10      阅读:140      评论:0      收藏:0      [点我收藏+]

技术分享图片

 

题意:N个数,按顺序划分为K组,使得逆序对之和最小。

思路:之前能用四边形不等式写的,一般网上都还有DP单调性分治的做法,今天也尝试用后者写(抄)了一遍。即:

分成K组,我们进行K-1次分治,get(l,r,L,R)中如果mid位置的最优解来自MID,那么分别以mid和MID和分界线,有get(l,mid-1,L,MID);get(mid+1,r,MID,R);

 区间逆序对没有什么特别高效的方法,我们用莫对跑ok了。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=40010;
int a[maxn],sum[maxn],dp[maxn],ans[maxn],N,K,ql,qr,cost;
inline int query(int x){int res=0;while(x){ res+=sum[x]; x-=(-x)&x;} return res;}
inline void add(int x,int val){while(x<=N){ sum[x]+=val; x+=(-x)&x;} }
inline void move(int l,int r)
{
    while(ql>l) cost+=query(a[--ql]-1),add(a[ql],1);
    while(qr<r) cost+=query(N)-query(a[++qr]),add(a[qr],1);
    while(ql<l) add(a[ql],-1),cost-=query(a[ql++]-1);
    while(qr>r) add(a[qr],-1),cost-=query(N)-query(a[qr--]);
}
inline void get(int l,int r,int L,int R)
{
    if(l>r) return ;
    int mid=(l+r)>>1,Mid;
    for(int i=min(R+1,mid);i>L;i--){
        move(i,mid);
        if(dp[i-1]+cost<ans[mid]) {ans[mid]=dp[i-1]+cost; Mid=i-1;}
    }
    get(l,mid-1,L,Mid); get(mid+1,r,Mid,R);
}
int main()
{
    scanf("%d%d",&N,&K);
    rep(i,1,N) scanf("%d",&a[i]);
    rep(i,1,N) ans[i]=ans[i-1]+query(N)-query(a[i]),add(a[i],1);
    ql=1; qr=N; cost=ans[N];
    rep(i,2,K){
        memcpy(dp,ans,sizeof(ans)); //把上一轮的结果复制
        memset(ans,0x3f,sizeof(ans));
        get(1,N,0,N-1);
    }
    printf("%d\n",ans[N]);
    return 0;
}

 

BZOJ5125: [Lydsy1712月赛]小Q的书架(DP决策单调性)

原文:https://www.cnblogs.com/hua-dong/p/9963452.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!