zoukankan      html  css  js  c++  java
  • CF834D

    题目链接:http://codeforces.com/contest/834/problem/D

    题目大意:将一个有n个数的数列分成k段,每段的价值为该段中不同数字的个数,求k段的最大总价值。

    解题思路:

      思路来自叉姐 + GreenGrape

      dp + segment trees.

      dp不难想到。前 i 个数分成 j 段的最大价值:dp[i][j] = max( dp[i-1][k] + w(k+1,j), i-1 <= k < j). 但其实这样直接去搞的话分分钟TLE。

      所以,我们需要使用线段树。详情请看代码,里面有个人的注释,请指教。

    AC代码:

     1 #include <cstdio>
     2 #include <algorithm>
     3 #include <iostream>
     4 #include <cmath>
     5 #include <cstring>
     6 #include <vector>
     7 #include <map>
     8 #include <set>
     9 #include <stack>
    10 #include <string>
    11 #include <queue>
    12 
    13 using namespace std;
    14 #define lson l , m , rt << 1
    15 #define rson m + 1 , r , rt << 1 | 1
    16 #define root 1 , N , 1
    17 const int maxn=35000+5;
    18 int a[maxn],dp[52][maxn],last[maxn];
    19 int pre[maxn];
    20 int tree[maxn<<2],lazy[maxn<<2];
    21 
    22 //*****************************************************
    23 //这一部分其实就是走模板
    24 void pushup(int rt){
    25     tree[rt]=max(tree[rt<<1],tree[rt<<1|1]);
    26 }
    27 void pushdown(int rt){
    28     if(lazy[rt]){
    29         lazy[rt<<1]+=lazy[rt];
    30         lazy[rt<<1|1]+=lazy[rt];
    31         tree[rt<<1]+=lazy[rt];
    32         tree[rt<<1|1]+=lazy[rt];
    33         lazy[rt]=0;
    34     }
    35 }
    36 void update(int L,int R,int c,int l,int r,int rt){
    37     if(L<=l&&r<=R){
    38         lazy[rt]+=c;
    39         tree[rt]+=c;
    40         return;
    41     }
    42     pushdown(rt);
    43     int m=(l+r)>>1;
    44     if(L<=m)    update(L,R,c,lson);
    45     if(m<R)     update(L,R,c,rson);
    46     pushup(rt);
    47 }
    48 int query(int L,int R,int l,int r,int rt){
    49     if(L<=l&&r<=R)
    50         return tree[rt];
    51     pushdown(rt);
    52     int m=(l+r)>>1;
    53     int ret=0;
    54     if(L<=m)    ret=max(ret,query(L,R,lson));
    55     if(m<R) ret=max(ret,query(L,R,rson));
    56     return ret;
    57 }
    58 //*******************************************************
    59 
    60 
    61 int main(){
    62     int n,k;
    63     scanf("%d%d",&n,&k);
    64     for(int i=1;i<=n;i++){
    65         scanf("%d",&a[i]);
    66         pre[i]=last[a[i]];//pre[i]记录a[i]上一次出现的位置
    67         last[a[i]]=i;
    68     }
    69     for(int i=1;i<=k;i++){
    70         memset(tree,0,sizeof(tree));
    71         memset(lazy,0,sizeof(lazy));
    72         for(int j=i-1;j<=n;j++)
    73             update(j,j,dp[i-1][j],0,n,1);//把线段树各叶子结点的值初始化为dp[i-1][]的值,在dp[i][]这一维度上的操作其实就是在dp[i-1][]的基础上进行的。前面不能忘了把线段树的数据置0。
    74         for(int j=i;j<=n;j++){
    75 //对于以x为结尾(pre[j] <= x <= j-1)的dp[i-1][x],将a[j]作为第 i 段的结尾可以使得dp[i-1][x]对应的dp[i][j]的值+1。
    76 //故此时线段树维护的就是max(dp[i-1][k] + w(k+1,j), i-1 <= k < j)。w(k+1,j)在这个更新的过程中逐次加和累积。实在是精妙无比。
    77             update(pre[j],j-1,1,0,n,1);
    78             dp[i][j]=query(0,j,0,n,1);
    79         }
    80     }
    81     int ans=0;
    82     for(int j=k;j<=n;j++){
    83         if(dp[k][j]>ans)    ans=dp[k][j];
    84     }
    85     printf("%d
    ",ans);
    86     return 0;
    87 }
    “这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。”
  • 相关阅读:
    Tomcat和nginx负载均衡算法
    (转)CSS浮动(float,clear)通俗讲解
    MvcSiteMapProvider配置使用
    idea出现jdk版本过低导致无法通过编译
    java生成自己的doc文档
    RabbitMQ的应用场景
    java 变量和常量
    IDEA创建新空项目
    java中整型、浮点型、char型扩展
    java中数据类型占多少字节
  • 原文地址:https://www.cnblogs.com/Blogggggg/p/7352981.html
Copyright © 2011-2022 走看看