题目
数据范围
20% n ≤ \leq ≤ 100
100% n ≤ \leq ≤ 1000 , a[i] ≤ \leq ≤ 1e9
思路
- 先拿20分吧,枚举删除的长度和左节点位置 ,然后再**O(n)**看是否合法即可。
- 那么我们可以优化一下这个方法,显然如果删除长度为len的字串那么左右两边再多删几个,得到的序列也是合法的,所以我们可以二分优化一下。
- 当然,也可以
n
2
n^2
n2枚举左右端点,记录剩余序列中有多少个不同的元素,以及每个元素的个数,在以此往后推右端点的时候可以直接减去当前元素数量,当没有不同元素时即可结束。
细节方面可以离散化也可以打一个map
题外话
考场上花了1个多小时才写出来,真的蠢极了。想了一个假算法
记录每个元素出现的第一个,第二个,倒数第二个,倒数第一个位置,取min和max求一下长度。
后来被自己造的一组数据:1 3 2 1 2 4 3 4 hack了,就打了个暴力看数据后发现是正解,尽管还是因为标记数组没用map爆0(re)了,但是数据大点,我也要挂的。
呜呜呜,什么时候才能不这么蠢蛙。
代码
二分
int l=0,r=n;
while(l<=r)
{
int mid=(l+r)>>1;
if(check()) ans=mid,r=mid-1;
else l=mid+1;
}
离散化(不去重)
const int N=1e5+10;
int a[N],b[N];
for(int i=1;i<=n;i++) a[i]=b[i]=read();
sort(b+1,b+1+n);
for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+1+n,a[i])-b;
离散化(去重)
const int N=1e5+10;
int a[N],b[N];
for(int i=1;i<=n;i++) a[i]=b[i]=read();
sort(b+1,b+1+n);
int tot=unique(b+1,b+1+n)-(b+1);
for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+1+tot,a[i])-b;
正解
#include<bits/stdc++.h>
using namespace std;
int n,a[1010],flag=1;
map<int,int> dic,b;
int min1=100000,max1=-1000;
int vis[100000];
inline int read()
{
int Num=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-1; ch=getchar();}
while(ch>='0'&&ch<='9') {Num=(Num<<1)+(Num<<3)+ch-'0'; ch=getchar();}
return Num*f;
}
inline bool check(int r,int l)
{
for(int i=1;i<=n;i++) dic[a[i]]=0;
for(int i=1;i<r;i++)
{
if(dic[a[i]]) return false;
dic[a[i]]++;
}
for(int i=l+1;i<=n;i++)
{
if(dic[a[i]]) return false;
dic[a[i]]++;
}
return true;
}
int main()
{
n=read();
for(int i=1;i<=n;i++)
{
a[i]=read();
b[a[i]]++;
if(b[a[i]]>1) flag=0;
}
if(flag) {puts("0"); return 0;}
int l=0,r=n,ans=0;
while(l<=r)
{
int len=(l+r)>>1,flag=1;
for(int i=1;i+len<=n;i++) if(check(i,i+len)) ans=len,r=len-1,flag=0;
if(flag) l=len+1;
}
cout<<ans+1;
return 0;
}