国庆清北 Day5 T3 holyshit

一道神题 (holyshit)

Time Limit:1000ms   Memory Limit:128MB

 

题目描述

LYK有n个数ai。

它想找两段互不相交的区间。

要求:不存在一个数在这两段区间中总共的出现次数超过1次。

LYK想使得取出的两段区间的长度的和尽可能大。

问这个值最大是多少。

 

输入格式(holyshit.in)

    第一行一个数n。

接下来一行n个数ai。

 

输出格式(holyshit.out)

    一个数表示可能的最大值是多少

 

输入样例

10

3 1 2 1 2 4 5 4 5 6

 

输出样例

6

 

样例解释

取区间[1,3]和[8,10]是最优的。

 

数据范围

对于20%的数据n<=10。

对于40%的数据n<=50。

对于60%的数据n<=200。

对于100%的数据2<=n<=2000,1<=ai<=n。

 

g[i][j] 表示 [i,j]取一段子区间,没有元素重复,使得子区间长度最长 n^2
g[i][j-1] g[i+1][j] [i,j]没有元素重复

1 for (i=n; i>=1; i--){
2   for (j=1; j<=n; j++) v[j]=false; FLAG=true; 
3   for (j=i; j<=n; j++){
4     if (v[a[j]]) FLAG=false;
5     v[a[j]]=true;
6     if (FLAG) g[i][j]=j-i+1; else g[i][j]=max(g[i+1][j],g[i][j-1]);
7   }
8 }

先把所有符合条件的区间全部搞出来,由这些区间取扩展到g更大
[A,B]是合法的, 则 g[A][B]=B-A+1 g[l][r] l<=A r>=B 都有g[l][r]>=B-A+1 n^2

先枚举第一段区间的右端点r,当l=1时,求出所有×的位置,并求出第二段区间能取的最大长度。
随着l往右走,部分×被解锁,更新第二段区间的最大长度(并查集实现),然后更新答案。

f[i]表示在并查集树上的父亲,i的祖先就表示从i出发向右最近×的位置。

x这个位置被解锁了,getf(x+1)表示新增的区间右端点在哪里, 更新f呢,f[x]=getf(x+1);

 

posted @ 2018-10-05 16:29  lcan  阅读(133)  评论(0编辑  收藏  举报