Codeforces 834D The Bakery 【线段树优化DP】*

Codeforces 834D The Bakery


LINK


题目大意是给你一个长度为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 }
原文地址:https://www.cnblogs.com/dream-maker-yk/p/9676268.html