NKOJ——P1095——气球游戏

时间限制 : 15000 MS 空间限制 : 65536 KB 评测说明 : 1s,64m

  • 原题
    • 问题描述
    • 输入格式
    • 输出格式
    • 样例
      • 样例 1
        • 样例输入 1
        • 样例输出 1
      • 样例 2
        • 样例输入 2
        • 样例输出 2
    • 提示
  • 题解

原题

问题描述

何老板在磁器口摆摊提供打气球游戏。就是在一大块布上挂满各种颜色的小气球,游客可以花钱购买气枪子弹,然后用何老板提供的气枪在远处射击气球。
何老板提供了一种奖励,就是如果在连续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;

b u t . . . \Large but... but...

Time Limit Exceeded (10)
呃……
NKOJ——P1095——气球游戏_第1张图片


经过分析,我们发现时间主要耗在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不就正好吗?
NKOJ——P1095——气球游戏_第2张图片
于是乎……改了改:

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;
}

a t    l a s t : \Large at\;last: atlast:

Accepted (100)
代码见链接。
完结撒花!

你可能感兴趣的:(NKOJ——P1095——气球游戏)