Codeforces Round #426 (Div. 2) D. The Bakery(线段树维护dp)

题目链接: Codeforces Round #426 (Div. 2) D. The Bakery

题意:

给你n个数,划分为k段,每段的价值为这一段不同的数的个数,问如何划分,使得价值最大。

题解:

考虑dp[i][j]表示划分为前j个数划分为i段的最大价值,那么这就是一个n*n*k的dp,

考虑转移方程dp[i][j]=max{dp[i][k]+val[k+1][j]},我们用线段树去维护这个max,线段树上每个节点维护的值是dp[i][k]+val[k+1][j],对于每加进来的一个数a[j],他只会影响last[a[j]]~j-1这段区间,所以线段树将这段区间加1。dp[i][j]就是区间最大值。

 1 #include<bits/stdc++.h>
 2 #define F(i,a,b) for(int i=(a);i<=(b);++i)
 3 inline int RT(int l,int r){return l+r|l!=r;}
 4 using namespace std;
 5 
 6 const int N=40000;
 7 int n,k,mx[N*2],lazy[N*2],dp[N],a[N],la[N],pos[N];
 8 
 9 void build(int l=0,int r=n)
10 {
11     int rt=RT(l,r),mid=l+r>>1;lazy[rt]=0;
12     if(l==r){mx[rt]=dp[l];return;}
13     build(l,mid),build(mid+1,r);
14     mx[rt]=max(mx[RT(l,mid)],mx[RT(mid+1,r)]);
15 }
16 
17 void PD(int l,int r)
18 {
19     int rt=RT(l,r),ls=RT(l,l+r>>1),rs=RT((l+r>>1)+1,r);
20     lazy[ls]+=lazy[rt],lazy[rs]+=lazy[rt];
21     mx[ls]+=lazy[rt],mx[rs]+=lazy[rt];
22     lazy[rt]=0;
23 }
24 
25 void update(int L,int R,int v,int l=0,int r=n)
26 {
27     int rt=RT(l,r),mid=l+r>>1;
28     if(L<=l&&r<=R){mx[rt]+=v,lazy[rt]+=v;return;}
29     if(lazy[rt])PD(l,r);
30     if(L<=mid)update(L,R,v,l,mid);
31     if(R>mid)update(L,R,v,mid+1,r);
32     mx[rt]=max(mx[RT(l,mid)],mx[RT(mid+1,r)]);
33 }
34 
35 int ask(int L,int R,int l=0,int r=n)
36 {
37     int rt=RT(l,r),mid=l+r>>1,ans=0;
38     if(L<=l&&r<=R)return mx[rt];
39     if(lazy[rt])PD(l,r);
40     if(L<=mid)ans=max(ans,ask(L,R,l,mid));
41     if(R>mid)ans=max(ans,ask(L,R,mid+1,r));
42     return ans;
43 }
44 
45 int main(){
46     scanf("%d%d",&n,&k);
47     F(i,1,n)scanf("%d",a+i),pos[i]=la[a[i]],la[a[i]]=i;
48     F(i,1,k)
49     {
50         build();
51         F(j,1,n)update(pos[j],j-1,1),dp[j]=ask(0,j-1);
52     }
53     printf("%d
",dp[n]);
54     return 0;
55 }
View Code
原文地址:https://www.cnblogs.com/bin-gege/p/7276860.html