題解:CF1623B Game on Ranges

dujiaqi122899發表於2024-03-28

題意理解(建議先自己把原題描述看一遍再來看我的理解)

有一個集合,這個集合的元素是區間,一開始集合裡只有一個元素就是 \([1,n]\) 的區間,對這個集合我們可以選擇其中的一個元素(區間),然後在區間內選一個數d,以 \([l,d-1]\)\([d+1,r]\) 這兩個區間替換掉我們選擇的這個區間( \(l\)\(r\) 分別是我們從集合裡面選擇出來的這個元素的左端點和右端點)。當然這兩個新區間必須存在才行,左端點小於等於右端點。如果不存在就不加入到集合中。我們選擇\(n\)個數後,集合內元素個數為 \(0\),也就是區間個數為 \(0\) 時結束。

現在題目給出的是每次操作時選擇的那個區間,要你推出對應的d。比如現在有一個集合 \(S\),裡面有一個元素,區間\([1,6]\)

    第一次操作,選[1,6],d取2,對S,刪去[1,6],加入[1,1]和[3,6],現S={[1,1],[3,6]}。

    第二次操作,選[1,1]進行操作,d取1,對S,刪去[1,1],現S={[3,6]}。

    第三次操作,選[3,6]進行操作,d取6,對S,刪去[3,6],加入[3,5],現S={[3,5]}。

    第四次操作,選[3,5]進行操作,d取3,對S,刪去[3,5],加入[4,5],現S={[4,5]}。

    第五次操作,選[4,5]進行操作,d取5,對S,刪去[4,5],加入[4,4],現S={[4,4]}。

    第六次操作,選[4,4]進行操作,d取4,對S,刪去[4,4],現S為空,遊戲結束。

現題目打亂順序的給出 $[1,6],[1,1],[3,6],[3,5],[4,5],[4,4] $這六個區間,要求你推出每個區間對應的d,並輸出,可以不按照題目的順序。

題解

看似很複雜的一道題,我們可以從簡單的角度入手,對於左右端點相等的區間,\(d\) 只能選擇端點值,所以我們先確定所有左右端點相等區間對應的 \(d\) 值。其實我們可以簡單的理解為每次操作刪掉 \([1,n]\) 之間的一個數,所以刪過的數就不可能再次出現,也就是每個區間對應的\(d\)值都不相同。所以我們標記掉出現過的 \(d\)。於是我們有了這樣一個思路,隨著迭代的進行被標記的 \(d\) 越來越多,對於區間越來越大,但是找到 \(d\) 的難度相當,因為區間越大時被標記的 \(d\) 就越多。我們將區間以從小到大的順序排列,對於長度為 \(1\) 的區間直接找到 \(d\) 值,對於長度為 \(2\) 的區間只有兩個可能的 \(d\) 值,但此前我們標記了一個 \(d\) 值,所以對於長度為 \(2\) 的區間也只有一個確定的 \(d\) 值,以此類推。所有的區間我們都能找到一個 \(d\) 值與之對應。


#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define LM LLONG_MAX
#define IM INT_MAX
#define N 1001
struct pair1{
	int l;
	int r;
	int len;
	int d=0;
};
bool cmp(pair1 a,pair1 b){
	return a.len<b.len;
}
 
int main(){
	int t;
	
	cin>>t;
	while(t--){
		bool vis1[N]={0};
		int n,ans[N];
		cin>>n;
		pair1 a[N];
		for(int i=1;i<=n;i++){
			cin>>a[i].l>>a[i].r;
			a[i].len=a[i].r-a[i].l;
		}
		sort(a+1,a+1+n,cmp);
		for(int i=1;i<=n;i++){
			if(a[i].l==a[i].r){
				a[i].d=a[i].l;
				vis1[a[i].d]=true;
			}
			else {
				for(int j=a[i].l;j<=a[i].r;j++){
					if(!vis1[j]){
						a[i].d=j;
						vis1[j]=true;
					}
				}
			}
		}
		for(int i=1;i<=n;i++) cout<<a[i].l<<" "<<a[i].r<<" "<<a[i].d<<endl;
	}
}

相關文章