题目:
现在有n个人,题目给出了他们每个人所在市县的编号。他们站在一个从左向右的队伍中。小L不在队列中。他想找到一个长度不超过D的区域,使他能够找到最多的不同地方的朋友。要求输出能找到的朋友所在不同市县的最大数和找到这些朋友的最小区间长度。比如在整个队伍内他按从左向右顺序找到了3个A地朋友,1个B地朋友,1个C地朋友。假设D=5,那么不同市县的最大数为3(A地、B地、C地),最小区间长度为3(只须结交A地的最右面的一个人即可得到最大市县数3,因此区间长度不是5而是3)。假设在队伍内的人他都还没有结交。
在这里写题解时,我总算是长吐了一口气。(因为vijos1000-1653的大部分数据我都有,而此题我没有数据,要是做错了话,是很难修改的)那么,我就把我一步步的想法写下来。
望到100万的数据,肯定是O(n)或是O(log(n)*n)。代码一:
#include
using namespace std;
long a[1000001],t,last,ans,ans2,i,max,n;
bool check(long k)
{
long i;
for (i=1;i<=n-k+1;i++)
if (a[i+k-1]-a[i-1]==ans) returntrue;
return false;
}
long erfen(long l,long r)
{
long mid;
mid=(l+r)/2;
if (check(mid)) return erfen(l,mid);
else return erfen(mid+1,r);
}
int main()
{
scanf("%ld %ld",&n,&max);
last=-1;
for (i=1;i<=n;i++)
{
scanf("%ld",&t);
if (t!=last)a[i]=a[i-1]+1;
else a[i]=a[i-1];
last=t;
}
for (i=1;i<=n-max+1;i++)
if (a[i+max-1]-a[i-1]>ans)ans=a[i+max-1]-a[i-1];
printf("%ld ",ans);
ans2=erfen(1,max);
printf("%ld",ans2);
return 0;
}
代码二:
#include
using namespace std;
longa[1000001],s[32769],t,last,ans,ans2,i,max,n,cnt;
bool check(long k)
{
long i;cnt=0;
for (i=1;i<=32768;i++)s[i]=0;//以前是i<=n
for (i=1;i<=k;i++)
{
s[a[i]]++;if (s[a[i]]==1)cnt++;
}
if (cnt==ans) return true;
for (i=k+1;i<=n;i++)
{
s[a[i]]++;if (s[a[i]]==1)cnt++;
s[a[i-k]]--;if (s[a[i-k]]==0)cnt--;
if (cnt==ans) returntrue;
}
return false;
}
long erfen(long l,long r)
{
long mid;
if (l==r) return l;
mid=(l+r)/2;
if (check(mid)) return erfen(l,mid);
else return erfen(mid+1,r);
}
int main()
{
scanf("%ld %ld",&n,&max);
cnt=0;
for (i=1;i<=n;i++)
{
scanf("%ld",&a[i]);
}
for (i=1;i<=32768;i++)s[i]=0;//以前是i<=n
for (i=1;i<=max;i++)
{
s[a[i]]++;if (s[a[i]]==1)cnt++;
}
if (cnt>ans) ans=cnt;
for (i=max+1;i<=n;i++)
{
s[a[i]]++;if (s[a[i]]==1)cnt++;
s[a[i-max]]--;if (s[a[i-max]]==0)cnt--;
if (cnt>ans)ans=cnt;
}
printf("%ld ",ans);
ans2=erfen(0,max);//以前是(1,max)
printf("%ld",ans2);
//scanf("%ld",&ans);
return 0;
}