2020牛客暑期多校训练营(第九场) Groundhog Playing Scissors

原题
题目描述
n n n天,每天穿一件衣服,第 i 天有 k i 件 衣 服 可 以 穿 , 穿 第 k_i 件衣服可以穿,穿第 ki穿穿j$件衣服的的权值为 a i j a_{ij} aij 。从 n n n天中选择 m m m天,求这 m m m天中,所穿衣服的权值最大与最小值的最小差是多少。
样例
输入

4 3
1 3
2 8 6
1 2
3 1 7 5

输出

2

思路
因为数据比较多,所以我们考虑一些必要的条件 : :
1 、 1、 1衣服的权值。
2 、 2、 2这是第几天要穿的衣服。
所以我们可以开结构体存储,输入时标记天数。
然后就用滑动窗口划过去即可 : :

  • 按照权值的大小排序。
  • 找到前 t m p tmp tmp件衣服包含 m m m个不同的天。
  • 然后在滑动过程中更新 a n s : ans: ans
    a n s = ans= ans=最大的权值 − - 最小的权值。
    因为之前已经排过序了,所以最大的权值就是右端点的权值,最小的权值就是左端点的权值。
  • 每右移左端点,就往右端点搜,更新右端点,直到搜到另一个包含 m m m个不同天的区间为止,右端点就是这个区间的右端点。
  • 重复上述搜索即可,直至搜索到 n n n
  • 答案就是 a n s ans ans
    代码
#include
#define ll long long 
using namespace std;
const int maxn=2e6+6;
struct node{int day,v;}a[maxn];
bool cmp(node x,node y){return x.v<y.v;}
int n,m,k,l=1,r,tmp,sum,ans=1e9;
bool vis[maxn];
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&k);
		for(int j=1;j<=k;j++)scanf("%d",&a[++sum].v),a[sum].day=i;
		//标记天数
	}
	sort(a+1,a+sum+1,cmp);//排序
	while(tmp<m)//找到前tmp件衣服包含m个不同的天
	{
		r++;
		if(!vis[a[r].day])vis[a[r].day]=1,tmp++;
	}
	while(r<=sum)//滑动
	{
		ans=min(ans,a[r].v-a[l].v);vis[a[l].day]=0;tmp--;l++;
		if(!vis[a[l].day])vis[a[l].day]=1,tmp++;
		while(tmp<m&&r<=sum)
		{
			r++;
			if(!vis[a[r].day])vis[a[r].day]=1,tmp++;
		}
	}
	printf("%d\n",ans);
}

你可能感兴趣的:(2020牛客暑期多校训练营(第九场) Groundhog Playing Scissors)