1. 程式人生 > 實用技巧 >[NOIP模擬]糖果機器

[NOIP模擬]糖果機器

題目

題目背景

在糖果廠裡,有一臺生產糖果的機器。機器有一排輸出口,編號從 \(1\)\(n\)。一顆糖果生產好後就會從某個輸出口掉出來。
糖果機在開始生產之前,它會列印一張列表,告訴工廠老闆,每顆糖果何時以及從哪個插槽掉出來。
工廠老闆可以在輸出槽下方安裝移動的機器人,以抓住掉落的糖果。
任何糖果都不能掉在地板。機器人以每秒移動一槽寬度的速度執行。 在生產過程開始之前,每個機器人可以安排到抓起第一個糖果的插槽位置。
由於機器人很昂貴,老闆希望安裝儘可能少的機器人。
編寫一個程式,完成以下兩個子任務。

子任務 \(1\):計算接住所有糖果所需機器人的最小數量。

子任務 \(2\):輸出哪個機器人應該接住哪個糖果。

輸入格式

\(1\) 行包含一個整數 \(n\),表示生產的糖果數。
接下來 \(n\) 行,每行包含一對整數 \(s_i, t_i\),分別表示第 \(i\) 顆糖果的輸出槽編號和完成時刻。 每對 \((s_i, t_i)\) 是唯一的。

輸出格式

輸出的第一行僅包含一個整數 \(w\),表示接住所有糖果所需的機器人最小數量。機器人編號從 \(1\)\(w\).

接下來 \(n\) 行,每行 \(3\) 個整數 \((s_i, t_i, w_i)\),表示 \(t_i\) 時刻,由輸出槽 \(s_i\) 產出的糖果由編號為 \(w_i\) 的機器人接住.

資料範圍

\(100\%\)

的資料, \(0 \leq s_i, t_i \leq 10^9\)

測試點編號 n 特殊性質
1~2 $ \leq 10^2$ \(w \leq 4\)
3~6 \(\leq 8 \times 10^3\)
7~10 \(\leq 10^5\)

每個測試點若只輸出子任務 \(1\) 的答案,可得到該測試點 \(50\%\) 的得分。

題解

導彈攔截都看不出來了 = A=.

考慮一個機器人在接完 \(i\) 糖果之後還可以去接 \(j\) 糖果需要滿足的條件,顯然是這個東西:

\[T_j-T_i\ge |S_j-S_i| \]

分兩種情況:

\(1^\circ\).如果 \(S_j\ge S_i\)

,那麼必須得滿足 \(T_j-T_i\ge S_j-S_i\),顯然地,如果前者滿足,亦滿足 \(T_j-T_i\ge S_i-S_j\).

\(2^\circ\).如果 \(S_j< S_i\),那麼必須得滿足 \(T_j-T_i\ge S_i-S_j\),顯然地,如果前者滿足,亦滿足 \(T_j-T_i\ge S_j-S_i\).

那麼上面兩種情況可以同意一下,即如果 \(i\) 糖果之後去接 \(j\) 糖果,必須滿足:

\[\begin{cases} T_j-T_i\ge S_i-S_j \\ T_j-T_i\ge S_j-S_i \end{cases} \]

我們整理一下這個柿子,得到這個約束條件

顯然,以 \((T_i-S_i,T_i+S_i)\) 為關鍵字的二維偏序,將第一維排序之後在第二維上做導彈攔截即可.

程式碼

#include<bits/stdc++.h>
using namespace std;
namespace IO{
	#define rep(i,l,r) for(int i=l,i##_end_=r;i<=i##_end_;++i)
	#define fep(i,l,r) for(int i=l,i##_end_=r;i>=i##_end_;--i)
	#define fi first
	#define se second
	#define Endl putchar('\n')
    #define writc(x,c) fwrit(x),putchar(c)
	typedef long long ll;
	typedef pair<int,int> pii;
	template<class T>inline T Max(const T x,const T y){return x<y?y:x;}
	template<class T>inline T Min(const T x,const T y){return x<y?x:y;}
	template<class T>inline T fab(const T x){return x<0?-x:x;}
	template<class T>inline void getMax(T& x,const T y){x=Max(x,y);}
	template<class T>inline void getMin(T& x,const T y){x=Min(x,y);}
	template<class T>T gcd(const T x,const T y){return y?gcd(y,x%y):x;}
	template<class T>inline T readin(T x){
		x=0;int f=0;char c;
		while((c=getchar())<'0' || '9'<c)if(c=='-')f=1;
		for(x=(c^48);'0'<=(c=getchar()) && c<='9';x=(x<<1)+(x<<3)+(c^48));
		return f?-x:x;
	}
    template<class T>void fwrit(const T x){
        if(x<0)return putchar('-'),fwrit(-x);
        if(x>9)fwrit(x/10);putchar(x%10^48);
    }
}
using namespace IO;

const int maxn=1e5;

int t[maxn+5],s[maxn+5];

struct node{int a,b,i;
    inline int operator <(const node rhs)const{
        return a==rhs.a?b<rhs.b:a<rhs.a;
    }
}p[maxn+5];
int n;

inline void Init(){
    n=readin(1);
    rep(i,1,n){
        s[i]=readin(1),t[i]=readin(1);
        p[i]=node{t[i]-s[i],t[i]+s[i],i};
    }sort(p+1,p+n+1);
}

struct ans_info{
    int s,t,w;
}ans[maxn+5];

int q[maxn+5],ed;

inline int find(const int x){
    if(!ed || q[ed]>x)return -1;
    int l=1,r=ed,mid,ret;
    while(l<=r){
        mid=l+r>>1;
        if(q[mid]<=x)ret=mid,r=mid-1;
        else l=mid+1;
    }return q[ret]<=x?ret:-1;
}
signed main(){
    // freopen("candy.in","r",stdin);
    // freopen("candy.out","w",stdout);
    Init();
    rep(i,1,n){
        int x=find(p[i].b);
        int id=p[i].i;
        if(x==-1){
            q[++ed]=p[i].b;
            ans[i]=ans_info{s[id],t[id],ed};
        }else{
            q[x]=p[i].b;
            ans[i]=ans_info{s[id],t[id],x};
        }
    }writc(ed,'\n');
    rep(i,1,n)writc(ans[i].s,' '),writc(ans[i].t,' '),writc(ans[i].w,'\n');
	return 0;
}