[决策单调性] CF833B

dpdp 满足决策单调性。

简略地证明一下:

p=opt(y)<q=opt(x)<x<yp = opt(y)< q = opt(x)<x<y。设 [i,j][i,j] 的权值为 w(j,i)w(j,i),可以得到:

dpk1,p1+w(p,y)>dpk1,q1+w(q,y)dp_{k-1,p-1} + w(p,y) > dp_{k-1,q-1} + w(q,y) dpk1,q1+w(q,x)>dpk1,p1+w(p,x)dp_{k-1,q-1} + w(q,x) > dp_{k-1,p-1} + w(p,x)

两式相加再去掉相同项:

w(p,y)+w(q,x)>w(q,y)+w(p,x)w(p,y) + w(q,x) > w(q,y) + w(p,x) w(p,y)w(p,x)>w(q,y)w(q,x)w(p,y) - w(p,x) > w(q,y) - w(q,x)

考虑他们的实际意义:

左边:AA[x+1,y],[p,x][x+1,y],[p,x] 中不重复的数的个数。
右边:BB[x+1,y],[q,x] [x+1,y],[q,x] 中不重复的数的个数。

因为 [p,x][p,x] 包含 [q,x][q,x] ,所以 ABA \leq B,矛盾。

所以 w(p,y)+w(q,x)w(q,y)+w(p,x)w(p,y) + w(q,x) \leq w(q,y) + w(p,x),满足决策单调性,就可以用分治来做了。

对于 w(i,j)w(i,j) 的求法,我们可以发现,这个东西很像莫队,并且要求很多次。不过有趣的是,看一下递归树,发现每次都是连续的一段,就可以按照双指针直接每次大力求。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 3.5e4+10;
int n,k;
int a[N],dp[52][N];

int L=1,R,s,t[N];
void u(int i,int f) {
	t[a[i]] += f;
	if(t[a[i]] == 0) s --;
	if(t[a[i]] == 1 && f == 1) s ++;
}
int w(int j,int i) {
	while(R<i) u(++R,1);
	while(L>j) u(--L,1);
	while(R>i) u(R--,-1);
	while(L<j) u(L++,-1);
	return s;
}

void fz(int k,int L,int R,int l,int r) {
	if(L > R) return; int mid = L+R >> 1, opt = l, wo = 0;
	for(int i=l;i<=min(mid,r);i++) {
		if(dp[k-1][i-1] + w(i,mid) > dp[k-1][opt-1] + wo) {// 别写 w(opt,mid) 
			wo = w(i,mid); opt = i;
		}
	}
	dp[k][mid] = dp[k-1][opt-1] + wo;
	fz(k,L,mid-1,l,opt), fz(k,mid+1,R,opt,r);
}
signed main() {
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	cin>>n>>k;
	for(int i=1;i<=n;i++) cin>>a[i];
	memset(dp,-0x3f,sizeof dp);
	dp[0][0] = 0;
	for(int i=1;i<=k;i++) {
		fz(i,1,n,1,n); 
	}
	cout<<dp[k][n]; 
	return 0;
}
posted @ 2024-05-30 14:50  cjrqwq  阅读(7)  评论(0)    收藏  举报  来源