[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 (adscn@qq.com)
@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;
}
posted @ 2019-08-16 21:33  Adscn  阅读(162)  评论(0编辑  收藏  举报