背景:
类似的题目。
题目传送门:
https://www.luogu.org/problemnew/show/P2564
https://www.luogu.org/problemnew/show/P3029
题意:
有
n
n
n个珠子,且有
m
m
m种颜色。现在你需要选出一段包含所有的颜色,且长度尽可能短,求最小长度。
思路:
还是很好想的。
我们先将珠子按照位置升序。
枚举最左边的珠子,一直找到最右边的珠子,使得其包含所有颜色,更新答案。
在枚举左边第二个珠子的时候,我们只需要将前一个珠子的贡献减去,然后同理在最右边的珠子往后搜即可。
时间复杂度:
Θ
(
n
l
o
g
n
)
\Theta(nlogn)
Θ(nlogn)(要排序)。
P 2564 P2564 P2564代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,ans=2147483647;
struct node{int x,pos;} a[1000010];
int tot[100];
bool cmp(node x,node y)
{
return x.pos<y.pos;
}
int main()
{
int t,x,op=0;
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d",&t);
for(int j=1;j<=t;j++)
{
a[++op].x=i;
scanf("%d",&a[op].pos);
}
}
sort(a+1,a+n+1,cmp);
int head=0,tail=0,cnt=0;
for(;head<=n;head++)
{
while(cnt<m&&tail<n)
{
tail++;
if(!tot[a[tail].x]) cnt++;
tot[a[tail].x]++;
}
if(cnt==m) ans=min(ans,a[tail].pos-a[head].pos);
tot[a[head].x]--;
if(!tot[a[head].x]) cnt--;
}
printf("%d",ans);
}
P 3029 P3029 P3029代码:
#include<cstdio>
#include<cstring>
#include<map>
#include<algorithm>
using namespace std;
map<int,int> MAP;
int n,m,ans=2147483647;
struct node{int x,pos;} a[50010];
int tot[50010];
bool cmp(node x,node y)
{
return x.pos<y.pos;
}
int main()
{
int tmp=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d %d",&a[i].pos,&a[i].x);
if(!MAP[a[i].x]) MAP[a[i].x]=++tmp,m++;
}
sort(a+1,a+n+1,cmp);
int head=1,tail=1,cnt=0;
tot[MAP[a[1].x]]=cnt=1;
for(;head<=n;head++)
{
while(cnt<m&&tail<n)
{
tail++;
if(!tot[MAP[a[tail].x]]) cnt++;
tot[MAP[a[tail].x]]++;
}
if(cnt==m) ans=min(ans,a[tail].pos-a[head].pos);
tot[MAP[a[head].x]]--;
if(!tot[MAP[a[head].x]]) cnt--;
}
printf("%d",ans);
}