Codeforces 834D The Bakery 【线段树优化DP】*
Codeforces 834D The Bakery
题目大意是给你一个长度为n的序列分成k段,每一段的贡献是这一段中不同的数的个数,求最大贡献
是第一次做线段树维护DP值的题
感觉还可以,虽然看了一下这题是用线段树维护DP值
然后说思路
有一个很显然的思路是这样的:
dpi,j表示前i个数分成j段的最大贡献
dpi,j=max(dpk,j−1+calc(k+1,i))
然后我们就可以对于每一层j用线段树维护起来
然后就非常愉快地发现dp[i][p]只会从dp[i−1][p−1]之前的DP值进行转移
所以可以发现每次可以错位建立线段树
然后现在考虑怎么维护calc(k+1,i)
我们可以把一段区间的贡献拆成每个点的贡献
显然位置i的数会对左端点位置在pre[i]+1~i的所有点产生加一的贡献(因为考虑的右端点在i)
所以每次判断一下区间加区间求和就好了
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 350010 4 int a[N],b[N]; 5 int dp[N][60]; 6 int las[N],pre[N]; 7 int n,k; 8 namespace Segment_Tree{ 9 #define MAXN N<<2 10 #define LD (t<<1) 11 #define RD (t<<1|1) 12 int maxv[MAXN],add[MAXN]; 13 void pushup(int t){maxv[t]=max(maxv[LD],maxv[RD]);} 14 void pushdown(int t){ 15 if(add[t]){ 16 maxv[LD]+=add[t],add[LD]+=add[t]; 17 maxv[RD]+=add[t],add[RD]+=add[t]; 18 add[t]=0; 19 } 20 } 21 void build(int t,int l,int r){ 22 if(l>r)return; 23 add[t]=0; 24 if(l==r){maxv[t]=a[l];return;} 25 int mid=(l+r)>>1; 26 build(LD,l,mid); 27 build(RD,mid+1,r); 28 pushup(t); 29 } 30 void modify(int t,int l,int r,int L,int R){ 31 if(l>r)return; 32 if(L<=l&&r<=R){maxv[t]++;add[t]++;return;} 33 pushdown(t); 34 int mid=(l+r)>>1; 35 if(R<=mid)modify(LD,l,mid,L,R); 36 else if(L>mid)modify(RD,mid+1,r,L,R); 37 else{ 38 modify(LD,l,mid,L,mid); 39 modify(RD,mid+1,r,mid+1,R); 40 } 41 pushup(t); 42 } 43 int query(int t,int l,int r,int L,int R){ 44 if(l>r)return 0; 45 if(L<=l&&r<=R)return maxv[t]; 46 pushdown(t); 47 int mid=(l+r)>>1; 48 int ans=0; 49 if(R<=mid)ans=query(LD,l,mid,L,R); 50 else if(L>mid)ans=query(RD,mid+1,r,L,R); 51 else ans=max(query(LD,l,mid,L,mid),query(RD,mid+1,r,mid+1,R)); 52 pushup(t); 53 return ans; 54 } 55 }; 56 int main(){ 57 scanf("%d%d",&n,&k); 58 for(int i=1;i<=n;i++)scanf("%d",&a[i]),b[i]=a[i]; 59 sort(b+1,b+n+1); 60 int tot=unique(b+1,b+n+1)-b-1; 61 for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+tot+1,a[i])-b; 62 for(int i=1;i<=n;i++)pre[i]=las[a[i]],las[a[i]]=i; 63 for(int i=1;i<=n;i++)dp[i][1]=dp[i-1][1]+(int)(pre[i]==0); 64 for(int j=2;j<=k;j++){ 65 for(int i=1;i<=n;i++)a[i]=dp[i-1][j-1]; 66 Segment_Tree::build(1,1,n); 67 for(int i=1;i<=n;i++){ 68 Segment_Tree::modify(1,1,n,pre[i]+1,i); 69 dp[i][j]=Segment_Tree::query(1,1,n,1,i); 70 } 71 } 72 printf("%d",dp[n][k]); 73 return 0; 74 }