[决策单调性] CF833B
满足决策单调性。
简略地证明一下:
设 。设 的权值为 ,可以得到:
两式相加再去掉相同项:
考虑他们的实际意义:
左边: 为 中不重复的数的个数。
右边: 为 中不重复的数的个数。
因为 包含 ,所以 ,矛盾。
所以 ,满足决策单调性,就可以用分治来做了。
对于 的求法,我们可以发现,这个东西很像莫队,并且要求很多次。不过有趣的是,看一下递归树,发现每次都是连续的一段,就可以按照双指针直接每次大力求。
#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;
}

浙公网安备 33010602011771号