洛谷P3029 [USACO11NOV]牛的阵容Cow Lineup

版权声明:我这么弱的蒟蒻,虽然博文不是很好,但也请标明转发地址喵! https://blog.csdn.net/ACerAndAKer/article/details/82928001

STL大法好&&双指针大法好

双指针是一个玄学的东西

总的来说就是用一个变量l指在一个左端点,然后用一个变量r向右扩展直到符合要求的区间的条件为止,这玩意貌似也叫尺取法??

这道题数据范围hin大怎么办?用map离散化一下就好了

具体实现

我们读入的时候,用map记录每个出现的种类,记录总数cnt

然后我们需要按下标排个序,然后再开始圈答案

然后下面用双指针,从l=1,r=1开始 向右扩展,r停止扩展的条件是l ~ r这个区间包含了cnt种牛,如何判断呢?用个map,记录每种牛出现的次数,没出现过就map[id]++,tot++,当tot==cnt时,就可以更新l,让l++,直到l ~ r这个区间包含的牛的种数小于cnt就好了,判断l这个位置的map[id]==1,等于1说明就这一头,所以tot–,然后必须要map[id]–,然后每次框到一个区间取min就好

代码

//By AcerMo
#include<map>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int M=50050;
int n,cnt;
int a[M],b[M],id[M],rk[M];
map<int,int>que;
map<int,bool>vis;
inline int read()
{
	int x=0;char ch=getchar();
	while (ch>'9'||ch<'0') ch=getchar();
	while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
	return x; 
}
inline bool cmp(int x,int y){return a[x]<a[y];}
signed main()
{
	n=read();
	for (int i=1;i<=n;i++)
	{
		a[i]=read(),b[i]=read(),id[i]=i;
		if (!vis[b[i]]) vis[b[i]]=1,cnt++;
	}
	sort(id+1,id+n+1,cmp);
	int l=1,r=1,tot=1,mi=2e9,f=0;
	if (tot==cnt) f=1,mi=a[id[1]]-1;
	que[b[id[1]]]++;
	while (r<=n)
	{
		if (!f)
		{
			if (r==n) break;
			r++;
			if (!que[b[id[r]]]) tot++;
			que[b[id[r]]]++;
			if (tot==cnt) mi=min(mi,a[id[r]]-a[id[l]]),f=1;
		}
		else 
		{
			if (que[b[id[l]]]==1) tot--,f=0;
			que[b[id[l++]]]--;
			if (f==1) mi=min(mi,a[id[r]]-a[id[l]]);
		}
	}
	cout<<mi;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/ACerAndAKer/article/details/82928001