2020牛客暑期多校第九场 F- Groundhog Looking Dowdy(尺取)

传送门


题目大意:

给出 n n n天,每天有若干件衣服,可以任选 m m m天然后每天选出一件衣服,问如何选择使得选取的 m m m件衣服中最大最小值的差值最小

思路:

如果我们不考虑天数,直接按权值排序,然后对于每个左边界,我们要找的就是恰好的第一个右边界使得这个区间内含有 m m m种衣服,这个区间显然是可变化的。这个问题很明显就是经典的尺取问题啊(比赛时傻逼了想到开头却没想到尺取),我们只需要维护一个两个指针并用数组记录衣服的种类个数

#include <bits/stdc++.h>
#include <unordered_map>
#include <unordered_set>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define ins insert
#define Vector Point
#define lowbit(x) (x&(-x))
#define mkp(x,y) make_pair(x,y)
#define mem(a,x) memset(a,x,sizeof a);
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<double,double> pdd;
const double eps=1e-8;
const double pi=acos(-1.0);
const int inf=0x3f3f3f3f;
const double dinf=1e300;
const ll INF=1e18;
const int Mod=1e9+7;
const int maxn=2e6+10;

struct node{
    int w,id;

    bool operator < (const node &p) const {
        return w<p.w;
    }
}a[maxn];

int b[maxn];

int main(){
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    //ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int n,m,cnt=0;
    scanf("%d%d",&n,&m);
    for(int i=1,x,w;i<=n;i++){
        scanf("%d",&x);
        for(int j=0;j<x;j++){
            scanf("%d",&w);
            a[cnt++]={w,i};
        }
    }
    sort(a,a+cnt);
    int l=0,r=0,num=0;
    int ans=inf;
    //for(int i=0;i
    while(l<cnt){
        while(r<cnt && num<m){
            if(!b[a[r].id]) num++;
            b[a[r].id]++;
            r++;
        }
        if(num<m) break;
        ans=min(ans,a[r-1].w-a[l].w);
        if(--b[a[l].id]==0) num--;
        l++;
    }
    printf("%d\n",ans);
    return 0;
}

你可能感兴趣的:(牛客比赛)