Codeforces 1041C Coffee Break

比赛时候简直脑抽......以为是个链表写了一个多小时最后跑的还没暴力模拟快

题意(精简):

给定一个有 $ n $ 个数的数组,将其分成尽量少的若干组,使得每一组中任意两个数字的差不小于给定的常数 $ d $ 。

题解:

用结构体存储标号,数值和答案,方便排序处理和输出。

使用单调队列维护,队列中的数字为「某个组上一个数字」,队首即为「所有组上一个数字中最小的那个」。

首先按数值由小到大排一下序,然后将第一个数字push进队列,开一组。

然后,对于接下来的每个数,有两个选择:继承到某个组的后面,或者为自己新开一个组。

检查队首:

·如果队首与当前数字的差值大于 $ d $ ,就把当前的数字继承到「队首数字所在的组」,将队首pop掉,将当前数字push进队尾。

·如果队首与当前数字的差值小于等于 $ d $ ,那么由于是单调队列,之后的元素只会更大,一定不会满足。

此时只能选择为这个数字新开一组,并将其push进队尾。

最后,输出总共开了多少组,然后将所有结构体按输入的顺序重新排好,依次输出所属的组号。

代码如下:


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
int n,m,d;
int cnt=0;//组号 
struct cof{
    int in,time,bl;//in:输入顺序 bl:belong,属于哪一组 
    cof(int in=0,int time=0,int bl=0):
        in(in),time(time),bl(bl){
            
        }
};
cof a[200050];
bool cmp1(const cof x,const cof y){
    return x.time<y.time;
}
bool cmp2(const cof x,const cof y){
    return x.in<y.in;
}
queue<cof>q;
int main(){
    scanf("%d%d%d",&n,&m,&d);
    for(int i(1);i<=n;i++){
        scanf("%d",&a[i].time);
        a[i].in=i;
    }
    sort(a+1,a+1+n,cmp1);
    cnt++;
    a[1].bl=cnt;
    q.push(a[1]);
    for(int i(2);i<=n;i++){
        if(a[i].time>q.front().time+d){//可以继承 
            a[i].bl=q.front().bl;
            q.pop();
            q.push(a[i]);
        }
        else{//新开一组 
            cnt++;
            a[i].bl=cnt;
            q.push(a[i]);
        }
    }
    sort(a+1,a+1+n,cmp2);
    printf("%d\n",cnt);
    for(int i(1);i<=n;i++)printf("%d ",a[i].bl);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/soul-M/p/9660311.html
今日推荐