[原创]HDU 2158 最短区间版大家来找碴 [思维]【杂类】

2017-01-15 23:22:04 Tabris_ 阅读数:410


博客爬取于2020-06-14 22:42:08
以下为正文

版权声明:本文为Tabris原创文章,未经博主允许不得私自转载。
https://blog.csdn.net/qq_33184171/article/details/54565617


题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=2158
--------------------------------------------------------------------------------.
最短区间版大家来找碴

Time Limit: 5000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1173 Accepted Submission(s): 442

Problem Description
给定一个序列,有N个整数,数值范围为[0,N)。
有M个询问,每次询问给定Q个整数,可能出现重复值。
要求找出一个最短区间,该区间要包含这Q个整数数值。
你能找的出来吗?

Input
第一行有两个整数N,M。(N<100000, M<1000)接着一行有N个整数。再有M个询问,每个询问的第一行有一个整数Q(Q<100),第二行跟着Q个整数。当N,M同时为0时,输入结束。

Output
请输出最短区间的长度。保证有解。

Sample Input
5 2
1 2 2 3 1
3
1 2 3
3
1 1 3
0 0

Sample Output
3
2

Hint

第二个查询,找到的区间是[4,5]

Author
Wiskey

Source
2008信息工程学院集训队——选拔赛
---------------------------------------------------------------------------------.

开始想暴力尺取法但是这样的话的话复杂度就变成了O(N*M) 1e8 不可取…

然后想来想去,也想不到有什么复杂度上更优的算法,
最后百度了一发题解,

思路 其实没什么难的,就是在细节上做了改善,使运算量减少了一点罢了,

基本就是先确定一个大概的范围,然后在枚举维护两个区间的界限而已.(心累…)

抄了个代码就交了

附本题代码
----------------------------------------------------------。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# include <bits/stdc++.h>
using namespace std;
const int N = 1e5+7;
/***********************************************************************/
int a[N],num[N],qq[111],pos[N],mark[N];

int main(){
int n,m;
while(~scanf("%d%d",&n,&m)&&(n||m)){
for(int i=0;i<n;i++) pos[i]=-1,mark[i]=0;
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
if(pos[a[i]]==-1) pos[a[i]]=i;
}

int sum,mi,s,q,tem,x;
for(int t=1;t<=m;t++){
sum = s = 0;
int l = n,r=-1;
scanf("%d",&q);
for(int i=0;i<q;i++){
scanf("%d",&x);
num[x]=0;
mark[x]=t;
if(pos[x]>r)r=pos[x];
if(pos[x]<l)l=pos[x];
}
for(int i=l;i<=r;++i)++num[a[i]];
mi = r-l+1,tem = r-l+1;
while(r<n){
--num[a[l]];
if(num[a[l]] == 0){
while(++r<n && a[r] != a[l])++num[a[r]];//维护r时区间[l,r]包含m个数
num[a[r]]=1;
}
while(++l<=r && mark[a[l]] != t);//l每次都到下一个输入过的点
if(r<n && mi>r-l+1)mi=r-l+1;
}
printf("%d\n",mi);
}
}
return 0;
}