• 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 }
  • 相关阅读:
    217. 存在重复元素
    189. 旋转数组
    122. 买卖股票的最佳时机 II
    26. 删除排序数组中的重复项
    [剑指Offer]二进制中1的个数
    [Unity]Unity更改黑色主题(个人版)
    [Unity]限制两个物体之间的距离
    [Untiy]贪吃蛇大作战(五)——游戏主界面
    sql server 函数详解(3)数据类型转换函数和文本图像函数
    sql server 函数详解(2)数学函数
  • 原文地址:https://www.cnblogs.com/dream-maker-yk/p/9676268.html
Copyright © 2020-2023  润新知