题意:

给出一个长度为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. idea 新建 maven项目遇到的一些问题

    idea创建好了maven项目之后,需要先在项目中添加 Web,这里创建Web时就会要求fix一个Artifacts,新建即可,然后面板设置默认即可(shift+ctrl+alt+s 打开面板): 然 ...

  2. 获取安卓app的appPackage和appActivity

    1.需要配置好android的开发环境后,打开cmd命令窗口 2.在命令窗口中输入,adb logcat>D:/log.log,抓取日志 3.运行启动app 4.查看日志log 5.搜索日志的关 ...

  3. Bug 级别定义标准

    缺陷种类 缺陷级别 详细说明 功能缺陷 Urgent (V级) 1.操作系统无法正常使用,死机,出现致命错误 2.数据丢失 3.被测试系统频繁崩溃,程序出错,使功能不能继续使用 4.性能与需求不一致 ...

  4. Linux 安装Redis<准备>(使用Mac远程访问)

    阅读本文需要一定的Linux基础 一 Redis简介 redis是用c语言编写的一款开源的高性能键值对(key-value)数据库 它通过提供多种键值数据类型来适应不同场景下的存储需求 二 Redis ...

  5. PytorchZerotoAll学习笔记(三)--自动求导

    Pytorch给我们提供了自动求导的函数,不用再自己再推导计算梯度的公式了 虽然有了自动求导的函数,但是这里我想给大家浅析一下:深度学习中的一个很重要的反向传播 references:https:// ...

  6. os模块大全详情

    python常用模块目录 一:os模块分类: python os.walk详解 二:os模块大全表 序号 方法 方法 1 os.access(path, mode) 检验权限模式 2 os.chdir ...

  7. socket编程 123

    1. 预备知识 一直以来很少看到有多少人使用php的socket模块来做一些事情,大概大家都把它定位在脚本语言的范畴内吧,但是其实php的socket模块可以做很多事情,包括做ftplist,http ...

  8. Friends and Cookies(思维)

    Abood's birthday has come, and his n friends are aligned in a single line from 1 to n, waiting for t ...

  9. scrum立会报告+燃尽图(第二周第五次)

    此作业要求参见:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2250 一.小组介绍 组名:杨老师粉丝群 组长:乔静玉 组员:吴奕瑶.公冶 ...

  10. Alpha阶段第2周/共2周 Scrum立会报告+燃尽图 02

    此次作业要求参见 [https://edu.cnblogs.com/campus/nenu/2018fall/homework/2285] Scrum master:祁玉 一.小组介绍 组长:王一可 ...