1. 程式人生 > >hdu 2158 最短區間版大家來找碴(尺取法)

hdu 2158 最短區間版大家來找碴(尺取法)

長度 names pan cstring code dir inpu memset fin

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 題意:要求找出一個最短區間,該區間要包含這Q個整數數值。 思路:尺取
#include <cstdio>
#include 
<map> #include <iostream> #include<cstring> #include<bits/stdc++.h> #define ll long long int #define M 6 using namespace std; inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;} inline ll lcm(ll a,ll b){return a/gcd(a,b)*b;} int moth[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
int dir[4][2]={1,0 ,0,1 ,-1,0 ,0,-1}; int dirs[8][2]={1,0 ,0,1 ,-1,0 ,0,-1, -1,-1 ,-1,1 ,1,-1 ,1,1}; const int inf=0x3f3f3f3f; const ll mod=1e9+7; int n,m,q; int a[100007]; //詢問數組 int temp[107]; bool vis[100007]; //標記為需求數 int num[100007]; //需求數的數量 int main(){ ios::sync_with_stdio(false); while(~scanf("
%d%d",&n,&m)){ if(!n&&!m) break; for(int i=1;i<=n;i++) scanf("%d",a+i); for(int i=1;i<=m;i++){ memset(vis,0,sizeof(vis)); memset(num,0,sizeof(num)); scanf("%d",&q); int sum=0; for(int j=1;j<=q;j++){ scanf("%d",temp+j); if(!vis[temp[j]]) vis[temp[j]]=1,sum++; } int ans=inf; int u,v,s; u=v=1; s=0; while(1){ while(v<=n&&s<sum){ if(vis[a[v]]&&!num[a[v]]) num[a[v]]++,s++; //如果是需求數且沒出現則s++ else if(num[a[v]]) num[a[v]]++;//不然只記錄下數目 v++; } if(s<sum) break; ans=min(ans,v-u); if(vis[a[u]]&&num[a[u]]==1) num[a[u]]--,s--; //與上面對應 else if(num[a[u]]>1) num[a[u]]--; u++; } cout<<ans<<endl; } } }

hdu 2158 最短區間版大家來找碴(尺取法)