[BZOJ5125]小Q的书架(决策单调性+分治DP+树状数组+莫队?)

\(O(n^2k)\)比较好想

\(dp[i][j]=\min\limits_{k<i}(dp[k][j-1]+w(k+1,i))\)

\(w\)就是逆序对个数。

打表发现有决策单调性。

但是我们发现逆序对个数不能很快的算,所以单调队列用不了了。

考虑分治,

\(solve(l,r,L,R,k)\)表示要计算的部位为\([l,r]\),可能决策点位于\([L,R]\)内,于是暴力算出\(mid\)的最优决策点\(p\),两边递归下去dp

/*
@Date    : 2019-08-16 21:14:43
@Author  : Adscn ([email protected])
@Link    : https://www.cnblogs.com/LLCSBlog
*/
#include<bits/stdc++.h>
using namespace std;
#define IL inline
#define RG register
#define int long long
#define gi getint()
#define gc getchar()
#define File(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
IL int getint()
{
    RG int xi=0;
    RG char ch=gc;
    bool f=0;
    while(ch<'0'||ch>'9')ch=='-'?f=1:f,ch=gc;
    while(ch>='0'&&ch<='9')xi=(xi<<1)+(xi<<3)+ch-48,ch=gc;
    return f?-xi:xi;
}
template<typename T>
IL void pi(T k,char ch=0)
{
    if(k<0)k=-k,putchar('-');
    if(k>=10)pi(k/10,0);
    putchar(k%10+'0');
    if(ch)putchar(ch);
}
const int N=4e4+7;
int n,K,sum;
int c[N],a[N],f[N][11];
void add(int k,int x){for(;k<=n;k+=k&-k)c[k]+=x;}
int qry(int x){int ans=0;for(;x;x-=x&-x)ans+=c[x];return ans;}
int L,R;
void move(int l,int r){
    while(L<l)sum-=qry(a[L]-1),add(a[L++],-1);
    while(L>l)sum+=qry(a[L-1]-1),add(a[--L],1);
    while(R<r)sum+=R-L+1-qry(a[R+1]),add(a[++R],1);
    while(R>r)sum-=R-L+1-qry(a[R]),add(a[R--],-1);
}
void solve(int l,int r,int L,int R,int now)
{
    if(l>r)return;
    int mid=(l+r)>>1,p=L;
    for(int i=L;i<=min(mid-1,R);++i)
    {
        move(i+1,mid);
        if(f[i][now-1]+sum<f[mid][now])f[mid][now]=f[i][now-1]+sum,p=i;
    }
    solve(l,mid-1,L,p,now);
    solve(mid+1,r,p,R,now);
}
signed main(void)
{
    n=gi,K=gi;
    for(int i=1;i<=n;++i)a[i]=gi;
    memset(f,127,sizeof f);
    L=1,R=0;
    for(int i=1;i<=n;++i)move(1,i),f[i][1]=sum;
    for(int i=2;i<=K;++i)solve(1,n,1,n,i);
    pi(f[n][K]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/LLCSBlog/p/11366472.html
今日推荐