kmjp's blog

競技プログラミング参加記です

AtCoder ARC #076 : F - Exhausted?

本番意外に苦戦してるな…。
https://atcoder.jp/contests/arc076/tasks/arc076_d

問題

座標1~Mの格子点それぞれにイスが1つずつある。
ここにN人の人がいる。
i番目の人は1~L[i]またはR[i]~Mの間のイスにしか座りたくない。
全員をイスに座らせるには、最大何個イスを追加すればよいか。

解法

M個のイスに最大何人人を座らせられるかを求めればよい。
一見区間スケジューリングの問題に近いが、人の座る範囲が2つに分かれているのがやりにくい。
ただ、1~Mの座標を直線とみなすのではなく、円環状になっていると考えよう。
そうすると結局各人は円環状のある1つの区間に座りたいことになる。

そこで円環状を2~3周しながら区間スケジューリング(座標順に見て、座れる位置が手前の人ほど優先して座らせる)を行い、1周の間で最大何人すわれるかを求めればよい。

int N,M;
vector<int> ev[602020];
int did[602020];

void solve() {
	int i,j,k,l,r,x,y; string s;
	
	int ret=0;
	cin>>N>>M;
	FOR(i,N) {
		cin>>x>>y;
		x+=M;
		ev[y].push_back(x);
		ev[y+M].push_back(x+M);
	}
	
	multiset<int> ed;
	int ma=0;
	FOR(i,3*M) {
		FORR(e,ev[i]) ed.insert(e);
		while(ed.size() && *ed.begin()<i) ed.erase(ed.begin());
		
		if(i) did[i]=did[i-1];
		if(ed.size()) {
			did[i]++;
			ed.erase(ed.begin());
		}
		if(i>M) ma=max(ma,did[i]-did[i-M]);
	}
	
	cout<<N-ma<<endl;
}

まとめ

数直線の両端をくっつけることに気が付けばあとは簡単。