题目大意:给出一串序列,询问最长的合法子串为多长,其中合法子串必须满足子串中[1,C]的数量大于等于K或者为0

题解:

定义右端点为包含某一点所需要的最小区间的右端点

那么初始化时就可以O(n)求出每个点的右端点

定义最小包含区间为某个点到其右端点的区间

定义不同的区间为当两个最小包含区间的最左边元素不同时两个区间为不同

那么不难想到,一个合法的子串,当且仅当所有最靠左边的不同的区间都被包含在子串内,此时子串合法

因此,不难想到当出现一个不合法区间时,将这个不合法区间的左端点作为分割点,分为左右两边进行递归操作

于是有了一个分治的做法,一开始询问子串[1,n]是否合法,若合法,则可能为答案,若不合法,则找到所有不合法的左端点,将其作为分割点分治下去

找不合法的左端点是复杂度瓶颈,我们考虑优化它

维护一个线段树,线段树维护最大的右端点,以及提供这个右端点的点在哪

那么不难想到每次只需要询问线段树[l,r]得到右端点看是否右端点大于r,大于则不合法,线段树返回的另一个值就是不合法点,将其作为分割点进行分治

考虑到所有相同的颜色我只需要最左边的还有用的,于是一开始时只需要把每个颜色最左边的区间加入线段树,分治时严格从左到右,删点时删除一个点的同时将删除点的颜色的下一个区间加入线段树,这样就能保证答案没有遗漏或者出错

因为每个点只会被加入一次和删除一次,所以时间复杂度为O(nlogn),可以通过此题

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#define INF 1000000007
using namespace std;
int n,c,k,tans;
int a[],nxt[],hd[];
int minsb[];
struct node
{
int p,minr;
}dat[*]; void pushup(int pos)
{
if(dat[pos<<].minr>=dat[pos<<|].minr)dat[pos]=dat[pos<<];
else dat[pos]=dat[pos<<|];
}
void change(int l,int r,int p,int v,int pos)
{
//printf("%d %d %d\n",l,r,p);
if(l==r && l==p)
{
dat[pos]=(node){p,v};
return;
}
int mid=l+r>>;
if(p<=mid)change(l,mid,p,v,pos<<);
else change(mid+,r,p,v,pos<<|);
pushup(pos);
}
node ask(int l,int r,int al,int ar,int pos)
{
if(l==al && r==ar)return dat[pos];
int mid=l+r>>;
node t1,t2;
if(ar<=mid)return ask(l,mid,al,ar,pos<<);
if(al>mid)return ask(mid+,r,al,ar,pos<<|);
t1=ask(l,mid,al,mid,pos<<);
t2=ask(mid+,r,mid+,ar,pos<<|);
if(t1.minr>=t2.minr)return t1;
else return t2;
}
void work(int l,int r)
{
//printf("%d %d\n",l,r);
if(l>r)return;
node td=ask(,n,l,r,);
//printf(" %d %d\n",td.p,td.minr);
if(l==r)
{
if(td.minr<=r)tans=max(tans,);
change(,n,l,,);
if(nxt[l])change(,n,nxt[l],minsb[nxt[l]],);
return;
}
if(td.minr>r)
{
work(l,td.p-);
change(,n,td.p,,);
if(nxt[td.p])change(,n,nxt[td.p],minsb[nxt[td.p]],);
work(td.p+,r);
}
else
{
tans=max(tans,r-l+);
for(int i=l;i<=r;i++)
{
//printf("*%d* %d\n",i,nxt[i]);
change(,n,i,,);
//printf("==-=-=-=-=-=-=\n");
if(nxt[i])change(,n,nxt[i],minsb[nxt[i]],);
}
return;
}
}
void init()
{
memset(a,,sizeof(a));
memset(nxt,,sizeof(nxt));
memset(hd,,sizeof(hd));
memset(minsb,,sizeof(minsb));
for(int i=;i<=n;i++)change(,n,i,,);
tans=;
}
int main()
{
while(scanf("%d%d%d",&n,&c,&k)!=EOF)
{
init();
for(int i=;i<=n;i++)scanf("%d",&a[i]);
for(int i=n;i>;i--)
{
nxt[i]=hd[a[i]];
hd[a[i]]=i;
}
for(int i=;i<=c;i++)
{
int t=hd[i],l=,j;
if(!t)continue;
j=t;
while(l<k && j)
{
j=nxt[j];
if(j)l++;
}
if((!j) || l<k)
{
while(t){minsb[t]=INF;t=nxt[t];}
}
else
{
while(t && j){minsb[t]=j;j=nxt[j];t=nxt[t];}
while(t){minsb[t]=INF;t=nxt[t];}
}
}
for(int i=;i<=c;i++)if(hd[i])change(,n,hd[i],minsb[hd[i]],);
work(,n);
printf("%d\n",tans);
//for(int i=1;i<=n;i++)printf("%d ",minsb[i]);
}
return ;
}

心得:考场上很快就想到了区间的做法,但是最后维护线段树时只放最左边的想法一直没有突破导致浪费了一点时间,还需要更加努力啊

【HDU6602】Longest Subarray【线段树+分治】的更多相关文章

  1. 2019杭电多校第二场hdu6602 Longest Subarray(线段树)

    Longest Subarray 题目传送门 解题思路 本题求一个最大的子区间,满足区间内的数字要么出现次数大于等于k次,要么没出现过.给定区间内的数字范围是1~c. 如果r为右边界,对于一种数字x, ...

  2. [2019杭电多校第二场][hdu6602]Longest Subarray(线段树)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6602 题目大意为求最长的区间,满足C种数字在区间内要么不出现,要么出现的次数都不小于K. 大致的分析一 ...

  3. 2019杭电多校二 L. Longest Subarray (线段树)

    大意: 给定序列$a$, 元素范围$[1,C]$, 求一个最长子序列, 满足每个元素要么不出现, 要么出现次数$\le K$. 枚举右端点, 考虑左端点合法的位置. 显然一定是$C$种颜色合法位置的交 ...

  4. HDU 6602 Longest Subarray (线段树)

    题意: 1e5的数组,c(1e5)种数字求最长的子串,使得其中每个出现的数字出现的次数为0次或者大于k次 思路: 枚举右端点i,维护当前右端点时,每个左端点的可行元素数量,当且仅当可行元素为c时更新答 ...

  5. HDU6602 Longest Subarray hdu多校第二场 线段树

    HDU6602 Longest Subarray 线段树 传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6602 题意: 给你一段区间,让你求最长的区间使 ...

  6. loj#2312. 「HAOI2017」八纵八横(线性基 线段树分治)

    题意 题目链接 Sol 线性基+线段树分治板子题.. 调起来有点自闭.. #include<bits/stdc++.h> #define fi first #define se secon ...

  7. BZOJ.4184.shallot(线段树分治 线性基)

    BZOJ 裸的线段树分治+线性基,就是跑的巨慢_(:з」∠)_ . 不知道他们都写的什么=-= //41652kb 11920ms #include <map> #include < ...

  8. BZOJ.4137.[FJOI2015]火星商店问题(线段树分治 可持久化Trie)

    BZOJ 洛谷 一直觉得自己非常zz呢.现在看来是真的=-= 注意题意描述有点问题,可以看BZOJ/洛谷讨论. 每个询问有两个限制区间,一是时间限制\([t-d+1,t]\),二是物品限制\([L,R ...

  9. 洛谷.3733.[HAOI2017]八纵八横(线性基 线段树分治 bitset)

    LOJ 洛谷 最基本的思路同BZOJ2115 Xor,将图中所有环的异或和插入线性基,求一下线性基中数的异或最大值. 用bitset优化一下,暴力的复杂度是\(O(\frac{qmL^2}{w})\) ...

  10. bzoj4025二分图(线段树分治 并查集)

    /* 思维难度几乎没有, 就是线段树分治check二分图 判断是否为二分图可以通过维护lct看看是否链接出奇环 然后发现不用lct, 并查集维护奇偶性即可 但是复杂度明明一样哈 */ #include ...

随机推荐

  1. mysql图形化管理工具workbench下载安装以及基本使用

    1.下载安装 去mysql官网下载地址进行下载安装 2. 创建schema和表格等基本操作 (1)连接数据库 打开workbench,操作如下: ps:正常需要输入mysql的密码的,但是我之前保存了 ...

  2. CentOS7下安装安装android sdk & gradle

    参考: 谢谢大佬! https://blog.csdn.net/jiangxuexuanshuang/article/details/88600574 主要就是安装sdk 与 gradle sdk下载 ...

  3. 高并发之CAS机制和ABA问题

    什么是CAS机制 CAS是英文单词Compare and Swap的缩写,翻译过来就是比较并替换 CAS机制中使用了3个基本操作数:内存地址V,旧的预期值A,要修改的新值B. 看如下几个例子: pac ...

  4. 记录MNIST采用卷积方式实现与理解

    从时间上来说,这篇文章写的完了,因为这个实验早就做完了:但从能力上来说,这篇文章出现的早了,因为很多地方我都还没有理解.如果不现在写,不知道什么时候会有时间是其一,另外一个原因是怕自己过段时间忘记. ...

  5. SQL 批量插入数据

    后面进行完善修改. /*批量插入数据*/ 这个比较完善.直接插入数据库表. INSERT INTO `goods_transverter` ( `code`,`es_id`,`barcode`, `n ...

  6. Django--Aadmin入门

  7. 用于拆解和组合PDF中各个对象的shell脚本

    拆解脚本 header_start=0 header_len=15 xref_start=$(strings -a -t d $1 | grep -e "\bxref\b" | a ...

  8. Selenium:三种等待方式详解

    我们在做WEB自动化时,一般要等待页面元素加载完成后,才能执行操作,否则会报找不到元素的错误,这样就要求我们在有些场景下加等待时间. 我们平常用到的有三种等待方式: 强制等待 隐式等待 显示等待 一. ...

  9. HDU3461_Code Lock

    Description 一排可以转动的密码锁,现在给你很多个区间,你可以操作同时转动这个区间内的密码锁,能够通过转动使之一样的密码锁为一种密码 如可以操作2~4这个区间:那么ABBB 和AAAA是一个 ...

  10. Vue.use

    不管是对象还是函数install 是Vue.use()必须要有的方法 否则无法使用(Vue.use(MintUI))但axios 不需要Vue.use(axios) 可以直接使用 因为axios没有i ...