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

题意: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
",ans[N]);
    return 0;
}

 我也写了四边形不等式来优化DP,其他部分一样。 然而T了,估计是莫对跑得太多了。

#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][11],pos[maxn][11],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--]);
}
int main()
{
    scanf("%d%d",&N,&K);
    rep(i,1,N) scanf("%d",&a[i]);
    memset(dp,0x3f,sizeof(dp)); dp[0][1]=0;
    rep(i,1,N) dp[i][1]=dp[i-1][1]+query(N)-query(a[i]),add(a[i],1);
    ql=1; qr=N; cost=dp[N][1];
    rep(i,2,K){
        rep(j,1,N){
           int L=pos[j][i-1]?pos[j][i-1]:1;
           int R=pos[j+1][i]?pos[j+1][i]:N-1;
           rep(k,L,R) {
               if(k>=j) continue;
               move(k+1,j);
               if(dp[j][i]>dp[k][i-1]+cost){
                   dp[j][i]=dp[k][i-1]+cost;
                   pos[j][i]=k;
               }
           }
        }
    }
    printf("%d
",dp[N][K]);
    return 0;
}
原文地址:https://www.cnblogs.com/hua-dong/p/9963452.html