原题
问题描述
何老板在磁器口摆摊提供打气球游戏。就是在一大块布上挂满各种颜色的小气球,游客可以花钱购买气枪子弹,然后用何老板提供的气枪在远处射击气球。
何老板提供了一种奖励,就是如果在连续T枪中打爆了所有颜色的气球,将得到一只泰迪熊作为奖励。(注意:不是所有的气球,而是所有颜色的气球,也就是每种颜色的气球至少被打爆一只)
总共有m种不同颜色的气球,编号1到m。一个游客买了n发子弹,然后连续开了n枪。何老板想知道在这n枪中,游客打爆所有颜色的气球,最少用了连续几枪?
输入格式
第一行两个空格间隔的整数数n,m。
第二行一共n个空格间隔的整数,分别表示每一枪打中的气球的颜色,0表示没打中任何颜色的气球。
输出格式
就一个整数,表示游客打爆所有颜色气球用的最少枪数。如果游客无法在这n枪打爆所有颜色的气球,则输出-1
样例
样例1
样例输入1
12 5
2 5 3 1 3 2 4 1 0 5 4 3
样例输出1
6
样例2
样例输入2
14 5
2 5 3 1 3 2 4 1 0 5 4 3 2 1
样例输出2
5
提示
30% n<=1000 m<=20。
100% n<=1000000 m<=2000。
样例1解释:有五种颜色的气球,编号1到5。游客从第2枪开始直到第7枪,这连续六枪打爆了 5 3 1 3 2 4这几种颜色的气球,包含了从1到5所有的颜色,所以最少枪数为6。
题解
首先,暴力求出第一个符合区间:
bool f=1;
ll n,m;
cin>>n>>m;
for(int i=0;i<n;i++)
{
cin>>e[i];
if(f&&(!bound(book,1,m+1,0)))
_min=tail=i+1,f=0;
}
接着,用队列,像车轮一样轧过去,队首出现在队中就head++
:
while(tail<n)
{
tail++;
while((e[head]==0)||bound(e,head+1,tail,e[head]))
head++;
if(tail-head<_min)
_min=tail-head;
}
最后:
cout<<_min;
return 0;
呃……晕_(¦3」∠)_
经过分析,我们发现时间主要耗在bound
上:
bool bound(ll e[],ll start,ll end,ll x)
{
for(ll i=start;i<end;i++)
if(e[i]==x)
return 1;
return 0;
}
如果建立一个表,查表不就快许多了吗?
前面那个book
不就是吗?
于是乎……改了改:
while(tail<=n)
{
while(e[head]==0||book[e[head]]>1)
book[e[head]]--,head++;
if(tail-head<_min)
_min=tail-head;
book[e[tail]]++;
tail++;
}
最后,特判没有任何区间:
if(f)
{
cout<<-1;
return 0;
}
代码
#include<iostream>
#define INT_MAX 2147483647
using namespace std;
typedef long long ll;
ll e[1000001],book[1000001],head,tail,_min=INT_MAX;
bool f=1;
bool bound(ll f[],ll start,ll end,ll x)
{
for(ll i=start;i<end;i++)
if(f[i]==x)
return 1;
return 0;
}
int main()
{
ll n,m;
cin>>n>>m;
for(int i=0;i<n;i++)
{
cin>>e[i];
if(f)
book[e[i]]++;
if(f&&(!bound(book,1,m+1,0)))
_min=tail=i+1,f=0;
}
if(f)
{
cout<<-1;
return 0;
}
while(tail<=n)
{
while(e[head]==0||book[e[head]]>1)
book[e[head]]--,head++;
if(tail-head<_min)
_min=tail-head;
book[e[tail]]++;
tail++;
}
cout<<_min;
return 0;
}
完结撒花!