【题意】n个数划分成k段,每段的价值为段内不同数字的数量,求最大总价值

【算法】DP+线段树

【题解】

f[i][j]表示前i个数字划分成j段的最大价值。

f[i][j]=max(f[k][j-1]+value(k+1,j)),j-1<=k<i。

暴力复杂度O(n^3*k),预处理value后复杂度降为O(n^2*k)。

正解考虑加入一个数字i,只能为k+1~i贡献1的价值,其中k为数字i上一次出现的位置。

那么排序预处理上一次出现位置,区间+1用线段树维护,取max用线段树查询,复杂度O(nk*log n)。

注意线段树常数……特别注意手写max。

从头查比从中间查常数小。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=;
struct tree{int l,r,ms,delta;}t[maxn*];
struct cyc{int num,ord;}b[maxn];
bool cmp(cyc a,cyc b){return a.num<b.num||(a.num==b.num&&a.ord<b.ord);}
int f[maxn],n,kind,a[maxn],c[maxn];
void pushup(int k){t[k].ms=max(t[k<<].ms,t[k<<|].ms);}
void pushdown(int k){
if(t[k].delta){
t[k<<].delta+=t[k].delta;
t[k<<].ms+=t[k].delta;
t[k<<|].delta+=t[k].delta;
t[k<<|].ms+=t[k].delta;
t[k].delta=;
}
}
void build(int k,int l,int r){
t[k].l=l;t[k].r=r;
if(l==r){t[k].ms=f[l];t[k].delta=;}
else{
int mid=(l+r)>>;
build(k<<,l,mid);
build(k<<|,mid+,r);
pushup(k);
t[k].delta=;
}
}
void insert(int k,int l,int r,int x){
if(l<=t[k].l&&t[k].r<=r){t[k].delta+=x;t[k].ms+=x;}
else{
pushdown(k);
int mid=(t[k].l+t[k].r)>>;
if(l<=mid)insert(k<<,l,r,x);
if(r>mid)insert(k<<|,l,r,x);
pushup(k);
}
}
int query(int k,int l,int r){
if(l<=t[k].l&&t[k].r<=r)return t[k].ms;
else{
pushdown(k);
int mid=(t[k].l+t[k].r)>>;
int ans=;
if(l<=mid)ans=query(k<<,l,r);
if(r>mid)ans=max(ans,query(k<<|,l,r));
return ans;
}
}
int main(){
scanf("%d%d",&n,&kind);
for(int i=;i<=n;i++){scanf("%d",&a[i]);b[i].num=a[i];b[i].ord=i;}
sort(b+,b+n+,cmp);
for(int i=;i<=n;i++)if(b[i].num==b[i-].num)c[b[i].ord]=b[i-].ord;
build(,,n);
for(int j=;j<=kind;j++){
for(int i=;i<=n;i++){
insert(,c[i],i-,);
f[i]=query(,,i-);
}
build(,,n);
}
printf("%d",f[n]);
return ;
}

暴力AC法:打表容易发现具有决策单调性,原因在于加入i时已知i-1的决策点j比左边优,加入i后对i上一次出现的位置到i有贡献,如果左边有贡献则j一定有贡献,所以决策点k>=j。

决策单调性可以用分支决策维护,复杂度O(n^2*k*log n)。

瓶颈在快速求区间数字个数,用主席树维护,复杂度O(nk*log n)。

#include<cstdio>
#include<cstring>
#include<cctype>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;
int read()
{
char c;int s=,t=;
while(!isdigit(c=getchar()))if(c=='-')t=-;
do{s=s*+c-'';}while(isdigit(c=getchar()));
return s*t;
}
/*------------------------------------------------------------*/
const int inf=0x3f3f3f3f,maxn=; int n,kind,f[][maxn],a[maxn],x,dfsnum=,b[maxn];
bool c[maxn];
int work(int x,int y){
dfsnum++;
int ans=;
for(int i=x;i<=y;i++)if(b[a[i]]!=dfsnum){
b[a[i]]=dfsnum;
ans++;
}
return ans;
}
void find(int l,int r,int L,int R)
{
if(l>r||L>R)return;
int mid=(l+r)>>;
int w,v=-inf+;
for(int i=L;i<=R&&i<mid;i++){
if(f[-x][i]+work(i+,mid)>v){
v=f[-x][i]+work(i+,mid);
w=i;
}
}
f[x][mid]=v;
find(l,mid-,L,w);
find(mid+,r,w,R);
}
int main()
{
scanf("%d%d",&n,&kind);
for(int i=;i<=n;i++)scanf("%d",&a[i]);
x=;
for(int j=;j<=kind;j++){
x=-x;
f[x][]=-inf;
find(,n,,n-);
}
printf("%d",f[x][n]);
return ;
}

O(n^2*k*log n)

【STSRM12】夏令营的更多相关文章

  1. 【STSRM12】夏令营(分治决策单调+主席树)

    [题意]n个数字分成k段,每一段的价值是段内不同数字的个数,求最大价值.n<=35000,k<=50. [算法]分治决策单调+主席树(可持久化线段树) [题解] f[i][j]表示前i天分 ...

  2. BUAA & ICT 夏令营之旅

    我还只有二十几岁,总应该相信点什么吧. ================================ 7.10午后坐火车赶到北京.一路上火车行驶在茫茫云海里.车窗外的世界是这样子的:一片广袤的原野 ...

  3. Thu夏令营 总结

    感觉这次thu夏令营简直就是爆RP啊 竟然签了无条件本一 [Waring]RP已空 话说这次考试设定 竟然是下午两点开始考试 考到五点- - 导致中午必须午睡 宾馆里清华也不近 按原本试机安排到12点 ...

  4. FZYZOJ-1578 [NOIP福建夏令营]数列分段

    P1578 -- [NOIP福建夏令营]数列分段 时间限制:1000MS      内存限制:131072KB 状态:Accepted      标签:    二分   无   无 Descripti ...

  5. 值得赞扬的尝试与进步——CSDN开源夏令营第一印象

    注:写这篇文章时我并未參加CSDN开源夏令营,也不确定是否会參加以及是否能參加上. 欣闻CSDN举办了"CSDN开源夏令营"活动.第一感觉是CSDN作为活动的组织者是很值得称赞的. ...

  6. 夏令营讲课内容整理 Day 7.

    Day7是夏令营的最后一天,这一天主要讲了骗分技巧和往年经典的一些NOIP试题以及比赛策略. 这天有个小插曲,上午的day7T3是一道和树有关的题,我是想破脑袋也想不出来,正解写不出来就写暴力吧,暴力 ...

  7. 夏令营提高班上午上机测试 Day 3 解题报告

    今天的题的确水.T3还是一道NOIP原题. 嘛,多刷点水题也不是什么坏事嘛. 说来也快,夏令营结束了整一星期了呢.大家也都回到了日常的暑假生活呢. 今天学业水平测试出成绩了...嗯结果还算满意呢,至少 ...

  8. 夏令营提高班上午上机测试 Day 2 解题报告

    那一天,日照一中夏令营数据结构提高班的同学们终于想起了,被Day2上午的三道题支配的恐惧……   是的..这一天的题有点难想.. 本来打算前天写这篇随笔,然而前天在机房和同学打luogu月赛…… 昨天 ...

  9. 浴谷夏令营例题Codeforces827DBest Edge Weight(三个愿望,一次满足~(大雾

    这题在浴谷夏令营wyx在讲的最小生成树的时候提到过,但并没有细讲怎么写... 这题可以用三种写法写,虽然只有两种能过...(倍增/倍增+并查集/树链剖分 先跑出最小生成树,分类讨论,在MST上的边,考 ...

随机推荐

  1. 【多线程】 Task ,async ,await

    [多线程]Task ,async ,await 一. WinForm 里经常会用到多线程, 多线程的好出就不多说了,来说说多线程比较麻烦的地方 1. UI 线程与其他线程的同步,主要是 Form 和 ...

  2. Hackerrank - [Algo] Matrix Rotation

    https://www.hackerrank.com/challenges/matrix-rotation-algo 又是一道耗了两小时以上的题,做完了才想起来,这不就是几年前在POJ上做过的一个同类 ...

  3. 【APUE】Chapter13 Daemon Processes

    这章节内容比较紧凑,主要有5部分: 1. 守护进程的特点 2. 守护进程的构造步骤及原理. 3. 守护进程示例:系统日志守护进程服务syslogd的相关函数. 4. Singe-Instance 守护 ...

  4. 微信营销 推广 会议签到 活动签到 复用微信3D动画签到系统

    适用场合 本软件适合各行各业,尤其世界500强上市公司,推广产品,聚集微信粉丝和人气.如大型展销会,新产品发布,主题活动推广,年会晚会等.各种商业和演出场合. 软件有试用版可供下载试用. 特色功能 顾 ...

  5. 【转】V8 之旅: 垃圾回收器

    垃圾回收器是一把十足的双刃剑.其好处是可以大幅简化程序的内存管理代码,因为内存管理无需程序员来操作,由此也减少了(但没有根除)长时间运转的程序的内存泄漏.对于某些程序员来说,它甚至能够提升代码的性能. ...

  6. pta指针作业

    #PTA实验作业 6-1 本题pta提交列表 设计思路 本题是一道简单的指针程序题,两个数已经分别被指针定义,只要把用其指针把二者加在一起和减去即可 调试过程 本题无调试过程 代码截图 6-2  1. ...

  7. js调用本地office打开服务器的office文件预览

    本来是想做成直接在网页上在线预览office文件的,但是找了好多,要不是收费,要不就是要调用别人的API不安全,所以纠结了好久还是用调用本地的office预览office文件. 废话不多说,那么怎么调 ...

  8. golang and intellij

    有一个项目,混合了java和go,需要在intellij中安装go的插件. OK,网上的信息简直混乱不堪,两个流派,一个流派就是装插件,一个流派就是编译插件,各种折腾,还是安装不了,谁知柳暗花明又一村 ...

  9. [Java] 各种常用函数

    1.writeInt()和readInt() 这两个函数并不是写入一个整数,读取一个整数.它们实际上是写入4个字节,读取4个字节. writeInt(int i)把i按四个字节,二进制形式写到输出流里 ...

  10. spring笔记(三)

    Spring 第二天: 1. 代理模式 2. Aop编程 3.Spring对Jdbc的支持 JdbcTemplate工具类 思考: 程序的“事务控制”, 可以用aop实现! 即只需要写一次,运行时候动 ...