http://codeforces.com/problemset/problem/834/D

将一个长度为n的序列分为k段

使得总价值最大一段区间的价值表示为区间内不同数字的个数

n<=35000,k<=50

这题的dp是十分显然的,用dp[i][j]表示前i个数字分成j段的最大值

状态转移方程就是 dp[i][j] = max(dp[i - 1][k] + dis[k + 1][j] | (0 <= k <= j - 1))

但是乍一想可能是个O(knn)的算法,仔细一想果然是。

考虑线段树的优化。显然根据状态转移方程,线段树维护的是dp[i - 1][k] + dis[k + 1][j]的最大值

也就是对每一层都build一次线段树,然后以此查询更新,时间复杂度是O(knlnn),看着十分科学

其中一个难点在于对颜色种类的维护,dis这个35k * 35k的数组肯定是存不下的,仔细一想其实不需要什么花里胡哨的操作,用一个pre数组存储上一个这个颜色出现的地方,当遇到这个颜色的时候,在线段树pre[x] + 1,x的位置全部加上1,意在pre[x] + 1到x出现了这个颜色,种类++;

然后整个思路就出来了,对于每一层状态,用一个build更新上一层的dp[i - 1][k],dis在查询的过程中动态更新,这种听起来就很像正解的做法一般就是正解。

#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
const int MAXBUF=;char buf[MAXBUF],*ps=buf,*pe=buf+;
inline bool isdigit(const char& n) {return (n>=''&&n<='');}
inline void rnext(){if(++ps==pe)pe=(ps=buf)+fread(buf,sizeof(char),sizeof(buf)/sizeof(char),stdin);}
template <class T> inline bool in(T &ans){
#ifdef VSCode
ans=;T f=;register char c;
do{c=getchar();if ('-'==c)f=-;}while(!isdigit(c)&&c!=EOF);
if(c==EOF)return false;do{ans=(ans<<)+(ans<<)+c-;
c=getchar();}while(isdigit(c)&&c!=EOF);ans*=f;return true;
#endif
#ifndef VSCode
ans =;T f=;if(ps==pe)return false;do{rnext();if('-'==*ps)f=-;}
while(!isdigit(*ps)&&ps!=pe);if(ps==pe)return false;do{ans=(ans<<)+(ans<<)+*ps-;
rnext();}while(isdigit(*ps)&&ps!=pe);ans*=f;return true;
#endif
}const int MAXOUT=;
char bufout[MAXOUT], outtmp[],*pout = bufout, *pend = bufout+MAXOUT;
inline void write(){fwrite(bufout,sizeof(char),pout-bufout,stdout);pout = bufout;}
inline void out_char(char c){*(pout++)=c;if(pout==pend)write();}
inline void out_str(char *s){while(*s){*(pout++)=*(s++);if(pout==pend)write();}}
template <class T>inline void out_int(T x) {if(!x){out_char('');return;}
if(x<)x=-x,out_char('-');int len=;while(x){outtmp[len++]=x%+;x/=;}outtmp[len]=;
for(int i=,j=len-;i<j;i++,j--) swap(outtmp[i],outtmp[j]);out_str(outtmp);}
template<typename T, typename... T2>
inline int in(T& value, T2&... value2) { in(value); return in(value2...); }
#define For(i, x, y) for(int i=x;i<=y;i++)
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))
#define Sca(x) scanf("%d", &x)
#define Scl(x) scanf("%lld",&x);
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second
#define Vec Point
typedef vector<int> VI;
const double eps = 1e-;
const int maxn = ;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + ;
int N,M,tmp,K;
int a[maxn];
int dp[maxn][]; //以这个结尾
int pre[maxn];
int display[maxn];
struct Tree{
int l,r;
int MAX,lazy;
}tree[maxn * ];
void Pushdown(int t){
if(tree[t].lazy){
tree[t << ].lazy += tree[t].lazy; tree[t << ].MAX += tree[t].lazy;
tree[t << | ].lazy += tree[t].lazy; tree[t << | ].MAX += tree[t].lazy;
tree[t].lazy = ;
}
}
void Pushup(int t){
tree[t].MAX = max(tree[t << ].MAX,tree[t << | ].MAX);
}
void Build(int t,int l,int r,int flag){
tree[t].l = l; tree[t].r = r;
tree[t].lazy = ;
if(l == r){
tree[t].MAX = dp[l - ][flag];
return;
}
int m = (l + r) >> ;
Build(t << ,l,m,flag);
Build(t << | ,m + ,r,flag);
Pushup(t);
}
void update(int t,int l,int r){
if(l <= tree[t].l && tree[t].r <= r){
tree[t].MAX++;
tree[t].lazy++;
return;
}
Pushdown(t);
int m = (tree[t].l + tree[t].r) >> ;
if(r <= m) update(t << ,l,r);
else if(l > m) update(t << | ,l,r);
else{
update(t << ,l,m);
update(t << | ,m + ,r);
}
Pushup(t);
}
int query(int t,int l,int r){
if(l <= tree[t].l && tree[t].r <= r){
return tree[t].MAX;
}
Pushdown(t);
int m = (tree[t].l + tree[t].r) >> ;
if(r <= m){
return query(t << ,l,r);
}else if(l > m){
return query(t << | ,l,r);
}else{
return max(query(t << | ,m + ,r),query(t << ,l,m));
}
}
int main()
{
in(N,K);
For(i,,N) display[i] = ;
For(i,,N){
in(a[i]);
pre[i] = display[a[i]];
display[a[i]] = i;
}
For(i,,K){ //dp[i][j] = max(dp[i - 1][k] + dis[k + 1][j]) (0 <= k <= j - 1));
Build(,,N,i - );
For(j,,N){
update(,pre[j] + ,j);
dp[j][i] = query(,,j);
// cout << dp[j][i] << " ";
}
// cout << endl;
}
Pri(dp[N][K]);
#ifdef VSCode
write();
system("pause");
#endif
return ;
}

CodeForces834D DP + 线段树的更多相关文章

  1. ZOJ 3349 Special Subsequence 简单DP + 线段树

    同 HDU 2836 只不过改成了求最长子串. DP+线段树单点修改+区间查最值. #include <cstdio> #include <cstring> #include ...

  2. hdu 3016 dp+线段树

    Man Down Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total S ...

  3. cf834D(dp+线段树区间最值,区间更新)

    题目链接: http://codeforces.com/contest/834/problem/D 题意: 每个数字代表一种颜色, 一个区间的美丽度为其中颜色的种数, 给出一个有 n 个元素的数组, ...

  4. Codeforces Round #620 F2. Animal Observation (hard version) (dp + 线段树)

    Codeforces Round #620 F2. Animal Observation (hard version) (dp + 线段树) 题目链接 题意 给定一个nm的矩阵,每行取2k的矩阵,求总 ...

  5. POJ1769 Minimizing maximizer(DP + 线段树)

    题目大概就是要,给一个由若干区间[Si,Ti]组成的序列,求最小长度的子序列,使这个子序列覆盖1到n这n个点. dp[i]表示从第0个到第i个区间且使用第i个区间,覆盖1到Ti所需的最少长度 对于Si ...

  6. [USACO2005][POJ3171]Cleaning Shifts(DP+线段树优化)

    题目:http://poj.org/problem?id=3171 题意:给你n个区间[a,b],每个区间都有一个费用c,要你用最小的费用覆盖区间[M,E] 分析:经典的区间覆盖问题,百度可以搜到这个 ...

  7. POJ 3162 Walking Race 树形DP+线段树

    给出一棵树,编号为1~n,给出数m 漂亮mm连续n天锻炼身体,每天会以节点i为起点,走到离i最远距离的节点 走了n天之后,mm想到知道自己这n天的锻炼效果 于是mm把这n天每一天走的距离记录在一起,成 ...

  8. 【uva1502/hdu4117-GRE Words】DP+线段树优化+AC自动机

    这题我的代码在hdu上AC,在uva上WA. 题意:按顺序输入n个串以及它的权值di,要求在其中选取一些串,前一个必须是后一个的子串.问d值的和最大是多少. (1≤n≤2×10^4 ,串的总长度< ...

  9. bzoj 1835 [ZJOI2010]base 基站选址(DP+线段树)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1835 [题意] 有n个村庄,每个村庄位于d[i],要求建立不多于k个基站,在第i个村庄 ...

随机推荐

  1. Linux内核分析第五周总结

    系统调用在内核代码中的工作机制和初始化 xyz()与sys_xyz()是通过系统调用号联系在一起的 0x80与system_call是通过中断向量联系起来的 系统调用机制的初始化 用汇编代码编写系统调 ...

  2. MyBatis中if,where,set标签

    <if>标签 <select id="findActiveBlogWithTitleLike" resultType="Blog"> S ...

  3. OSGB数据压缩

    OSGB数据输出时压缩数据大小,采用如下设置 osgDB::writeNodeFile(*osgbNode, "xxx/xxxx.osgb", new osgDB::Options ...

  4. Sublime Text3前端必备插件

    安装Package Control 在安装插件之前,需要让sublime安装Package Control.打开Sublime Text的控制台,快捷键ctrl + ~,在控制台中输入以下代码. im ...

  5. C++中struct 和 class的区别

    首先,C++中类的定义,从狭义上理解,就是我们使用的class类型.从广义上,类就是定义了一个新的类型和新的作用域,它具有成员函数和成员数据. 而对广义类定义的实现分为两种,一种是使用struct实现 ...

  6. 【转】使用screw plus对PHP源码加密

    运行环境 ubuntu 14.04 php 5.6 源码地址 https://github.com/del-xiong/screw-plus http://git.oschina.net/splot/ ...

  7. docker网络调试过程

    #1: 添加永久网桥 vi /etc/sysconfig/network-scripts/ifcfg-br0 DEVICE=br0 TYPE=Bridge BOOTROTO=static IPADDR ...

  8. CSS响应式网站开发

    <html> <head> //当设备屏幕最大宽度小于1024px时加载如下CSS内容 @media screen and (max-width: 1024px){       ...

  9. CentOS 使用SMB服务 让windows能够上传文件

    1. 新增加用户 useradd zhaobsh 2. 使用 pdbedit的方式新增加用户 pdbedit -a -u zhaobsh 3. 修改smb服务 systemctl restart sm ...

  10. C++与C的区别

    在最开始C++只是C加上了一些面向对象的特性,C++最初的名字为C with Classes.后来C++又提出了一些不同于Class的特性:Exceptions(异常).templates(模板).S ...