题意:

给出一个长度为n的序列,每个数值在1-n之间且为整数,现在要把这个序列划分为若干段,使得每一段的颜色种数不超过k,求最少的区间数目.对于从1到n的n种k的取值,分别输出这时的最少区间数目.

分析:

首先这个题很像HH的项链,而HH的项链的在线做法需要写可持久化线段树,我们自然想到这个题也需要可持久化线段树

考虑对于每个k分别求解.暴力的贪心做法是这样:从左端开始,每次找出一段尽量长的颜色种数不超过k的区间划分出来.如果颜色种数要求不超过k,那么划分的区间段数最多为n/k上取整.(k个元素一段即可).对于k的n种取值,一共最多要找nln(n)段区间.如果能在较低的复杂度(例如logn)内找出每一段区间,这个题就做出来了.

然后我的想法是类似bzoj4504 K个串,写了一发区间修改的可持久化线段树,然后每次在线段树上二分.Codeforces的官方题解大概相当于这个做法差分一下,不需要区间修改,只需要单点修改的可持久化线段树.

具体是:对于每个左端点L,我们求出一个数组f[L][],f[L][i]存储从L到i出现的不同颜色的种数(如果i<L那么f[L][i]=0).那么从F[L][]到F[L-1][],只有a[L-1]影响的一段区间的数值会+1,那么可以用可持久化线段树来维护这个序列.查询时如果二分答案,每次在线段树上查询是两个log,直接在线段树上二分(也就是在每个节点判断向左侧还是右侧递归求解)就是一个log的.我写了一发标记永久化.细节参见代码.

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=100005;
struct node{
int Max,mk;
node* ch[2];
node(){}
node(int x,int y){
ch[0]=ch[1]=0;Max=x;mk=y;
}
}t[maxn*60];int tsz=0;
node* root[maxn];
node* newnode(int x,int y){
t[++tsz]=node(x,y);return t+tsz;
}
int a[maxn];
int last[maxn];
void Insert(node* rt0,node* &rt,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr){
rt=newnode(rt0->Max+1,rt0->mk+1);
rt->ch[0]=rt0->ch[0];rt->ch[1]=rt0->ch[1];
}else{
rt=newnode(0,rt0->mk);
rt->ch[0]=rt0->ch[0];rt->ch[1]=rt0->ch[1];
int mid=(l+r)>>1;
if(ql<=mid)Insert(rt0->ch[0],rt->ch[0],l,mid,ql,qr);
if(qr>mid)Insert(rt0->ch[1],rt->ch[1],mid+1,r,ql,qr);
rt->Max=max(rt->ch[0]->Max,rt->ch[1]->Max)+rt0->mk;
}
}
int n;
int query(node* rt,int l,int r,int lim,int pre){
if(l==r){//printf("%d\n",pre);
if(pre+rt->Max>lim)return -1;
else return l;
}
int lmax=rt->ch[0]->Max+pre+rt->mk;
int mid=(l+r)>>1;
if(lmax>lim)return query(rt->ch[0],l,mid,lim,pre+rt->mk);
else if(lmax<lim)return query(rt->ch[1],mid+1,r,lim,pre+rt->mk);
int t=query(rt->ch[1],mid+1,r,lim,pre+rt->mk);
if(t==-1)return mid;
else return t;
}
int right(int s,int lim){
return query(root[s],1,n,lim,0);
}
int work(int lim){
int pt=1;
int ans=0;
while(pt<=n){
ans++;
pt=right(pt,lim)+1;//if(lim==1)printf("%d\n",pt);
}
return ans;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i)scanf("%d",a+i);
root[n+1]=newnode(0,0);
root[n+1]->ch[0]=root[n+1]->ch[1]=root[n+1];
for(int i=1;i<=n;++i)last[i]=n+1;
for(int i=n;i>=1;--i){
root[i]=root[i+1];
Insert(root[i],root[i],1,n,i,last[a[i]]-1);
last[a[i]]=i;
}
// printf("%d\n",query(root[1],1,n,1,0));return 0;
for(int i=1;i<=n;++i){
printf("%d ",work(i));
}
return 0;
}

Codeforces 786C Till I Collapse的更多相关文章

  1. Codeforces 786C Till I Collapse(树状数组+扫描线+倍增)

    [题目链接] http://codeforces.com/contest/786/problem/C [题目大意] 给出一个数列,问对于不同的k,将区间划分为几个, 每个区间出现不同元素个数不超过k时 ...

  2. Codeforces 786C. Till I Collapse 主席树

    题目大意: 给定一个长度为\(n\)的序列,要求将其划分为最少的若干段使得每段中不同的数字的种数不超过\(k\). 对于 \(k = 1 .. n\)输出所有的答案. \(n \leq 10^5\) ...

  3. Till I Collapse CodeForces - 786C (主席树区间加,二分最小值)

    大意: 给定序列, 将序列划分为若干段, 使得每段不同数字不超过k, 分别求出k=1...n时的答案. 考虑贪心, 对于某个k 从1开始, 每次查询最后一个颜色数<=k的点作为一个划分, 直到全 ...

  4. Codeforces 786 C. Till I Collapse

    题目链接:http://codeforces.com/contest/786/problem/C 大力膜了一发杜教的代码感觉十分的兹瓷啊! 我们知道如果$k$是给定的我们显然是可以直接一遍$O(n)$ ...

  5. CF786C Till I Collapse 整体二分+根号分治

    题意:对于一个序列,假如说一个区间内最多能包含 $k$ 个不同的数,那么这个序列最少会被划分成几个区间 $?$ 输出 $k$ 为 $1\sim n$ 的答案. 我们每次选区间一定是贪心地将这个区间选地 ...

  6. [cf787E]Till I Collapse

    考虑对询问分块,对于i<K的询问,暴力处理,时间复杂度为o(Kn):对于i>K的询问,发现答案都小于n/K且满足单调性,那么可以二分出每一段相同的答案,时间复杂度为$o(n^{2}log_ ...

  7. CF786C Till I Collapse

    题目分析 首先,对于这道题,可以用贪心以一个\(O(n)\)的复杂度求解一个\(k\)的值 暴力是\(O(n^2)\)的复杂度,当然过不了. 我们手推一下样例,会发现,答案满足单调性,于是,果断想到二 ...

  8. Codeforces Round #406 (Div. 1)

    B题打错调了半天,C题想出来来不及打,还好没有挂题 AC:AB Rank:96 Rating:2125+66->2191 A.Berzerk 题目大意:有一个东东在长度为n的环上(环上点编号0~ ...

  9. 【Codeforces Round #406 (Div. 2)】题解

    The Monster 签到题,算一下b+=a和d+=c,然后卡一下次数就可以了. Not Afraid 只要一组出现一对相反数就是安全的. Berzerk 题意:[1,n],两个人轮流走,谁能走到1 ...

随机推荐

  1. Luogu3804 【模板】后缀自动机

    题面 题解 一个串的出现次数等于$endpos$的大小,也是$parent$树上节点的$size$大小, 构建出后缀自动机,按拓补序,模拟即可. 代码 #include<cstdio> # ...

  2. 【LG3243】[HNOI2015]菜肴制作

    题面 洛谷 题解 首先我们有个非常显然的思路, 就是直接拓扑排序,用小根堆代替队列再按顺序输出,但是很显然是错的, 因为这只保证了字典序最小,而无法保证答案最优,\(<2,4>,<3 ...

  3. Python运维三十六式:用Python写一个简单的监控系统

    市面上有很多开源的监控系统:Cacti.Nagios.Zabbix.感觉都不符合我的需求,为什么不自己做一个呢? 用Python两个小时徒手撸了一个简易的监控系统,给大家分享一下,希望能对大家有所启发 ...

  4. SQL基本的45题

    -- 查询Student表中的所有记录的Sname.Ssex和Class列.SELECT Sname,Ssex,Class from student -- 查询教师所有的单位即不重复的Depart列. ...

  5. shell loop

    #!/bin/sh date i=0 while [ $i -le 30 ] do         echi $i /usr/sbin/r2/np_test_acl -f rule.txt i=$(e ...

  6. TW实习日记:第九天

    这两天有点忙,要改前端网页和加需求上去.所以昨天说的Vue缓存机制也没看,所以打算现在列个挖了的坑的清单: Vue缓存机制.生命周期和钩子函数 使用项目组自用组件来重写静态页面 SSM框架搭建.整合流 ...

  7. Spring Boot 整合JDBC 实现后端项目开发

    一.前言 二.新建Spring Boot 项目 三.Spring Boot 整合JDBC 与MySQL 交互 3.1 新建数据表skr_user 3.2 Jdbcproject 项目结构如下 3.3 ...

  8. 【坚持】Selenium+Python学习之从读懂代码开始 DAY1

    学习Selenium+Python已经好几个月了,但越学发现不懂的东西越多. 感觉最大的问题还是在于基础不扎实,决定从头开始,每天坚持读代码,写代码. 相信量变一定能到质变!!! 2018/05/09 ...

  9. Git + Gerrit 操作备忘

    Git review 作用 可以用来提交代码审核到Gerrit 安装 使用pip 安装 git-review 插件,执行 sudo -H pip install git-review 使用示例 可以参 ...

  10. Python基础灬序列(字符串、列表、元组)

    序列 序列是指它的成员都是有序排列,并且可以通过下标偏移量访问到它的一个或几个成员.序列包含字符串.列表.元组. 字符串 chinese_zodiac = '鼠牛虎兔龙蛇马羊猴鸡狗猪' print(c ...