欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Educational Codeforces Round 44 (Rated for Div. 2) E. Pencils and Boxes

程序员文章站 2022-06-04 09:58:12
...

E. Pencils and Boxes

Educational Codeforces Round 44 (Rated for Div. 2) E. Pencils and Boxes

这场cf D题的题意确是有点毒,于是乎比赛时我滚去做了E。

E题意:给你n个数字,让你将他们分成几个集合,集合中至少有k个数字,且集合中最大于最小的差值小于等于d

直观的想法,直接先sort一遍,由题意我们可以很容易发现如果可分,那么前k个必定在在一个集合中,那么之后就是一个贪心的问题了。
根据要求我们还可以得出另一个小推论:对于给定数组,在保证前m个集合都是可划最优size的情况下,当前下一个划分的集合的size越小差值越小。

然后,还有一个容易得到的小推论:对于任意一个以满足条件的集合,若是他的size足够大,从他里划分出的任意子集(size>=k)也都是满足题意的,所以说假设一个数组他是可分得,那么我们只要保证剩下的数的size,前面的集合的size可以尽量大,并且这不影响后面的数。如果该数组是不可分的,保证的剩下的size个必定是不满足的。

那么现在我们是需要判定是否可以一直贪心的划分到最后一位即可。

下面的解释直接写注释了,不然讲起来比较麻烦。

#include<cstdio>
#include<iomanip>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<vector>
#include<set>
#include<queue>
#include<limits.h>
#include<string.h>
#include<map>
#include<list>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

#define inf int(0x3f3f3f3f)
#define mod int(1e9+7)
#define eps double(1e-6)
#define pi acos(-1.0)
#define lson  root << 1
#define rson  root << 1 | 1


int n,k,d;

ll a[500005];

int vis[500005];

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin>>n>>k>>d;
    memset(vis,0,sizeof(vis));
    vis[0]=1;
    for(int i=1; i<=n; i++)
        cin>>a[i];
    sort(a+1,a+n+1);
    int cnt=1;
    int pre=0;
    int las=0;
    for(int i=k;i<=n;i++)
    {
        while(pre<=las&&a[i]-a[pre+1]>d)//pre<=las并且i从k开始即控制了size>=k
        {
            if(vis[pre])
                cnt--;
            pre++;
        }
        if(cnt>0)//cnt>0等价于集合size>=k
            vis[i]=1;
        las++;
        if(vis[las])
            cnt++;
    }
    if(vis[n])
        cout<<"YES"<<endl;
    else
        cout<<"NO"<<endl;
}