kmjp's blog

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

TopCoder SRM 580 Div1 Medium ShoutterDiv1

本番解けなかったMedium問題を復讐。
http://community.topcoder.com/stat?c=problem_statement&pm=12576

問題

N人(<=2500)の人がいて、それぞれS[i]~T[i]の時間教室にいる。
一瞬でも同じ時間教室にいた人っは友人である。

初期状態では、各人の自己紹介を友人が知っている。
ここで、各友人は自分が知ってる他人の1人分の自己紹介をrepostすることができる。
1回repostすると、その友人の友人にその1人分自己紹介を伝えることができる。
全員が全員分の自己紹介を知るために必要な最小のrepost数を答えよ。

解法

各人がrepost1回で伝えるのは1人分の自己紹介なので、それぞれの人の自己紹介は互いに関係ない。
よって、個々の人の自己紹介が全員に伝わるまでのrepost数の和をとればよい。

i番目の人はS[i]~T[i]の間教室にいるので、より前に教室にいる人と、より後に教室にいる人に徐々にrepostして自己紹介を伝えていけばよい。
ただこれ、両方向にrepostで伝える、と考えるとなかなかうまく解けなかった。

そこでEditorialを見て解答。
まずS[i]が昇順となるようにソートしておく。

i番目の人の自己紹介を全員に通知するには、T[j]が一番早い人から初めて、「1回repostすると、すでに自己紹介を知っている人のうち一番遅いT[j]に対し、S[k]がT[j]より早い人には自己紹介が到達する」と考えて全員に到達するまでのrepost数を数える。
本当はi番目の人から順に1番目に向けてrepostするけど、ここでは逆に1番目からi番目に到達するまでは逆順で必要回数を求める。

ここで、気が付くのは、上記手順にiが登場しないこと。
しかし、ここでT[j]がS[i]より大きい場合、S[i]へのrepostは1手とカウントされない、と考えればよい。
0手の時点でi番目の人(自分)は自己紹介を知ってるわけだしね。

class ShoutterDiv1 {
	public:
	int N;
	vector<pair<int,int> > S;
	string concatvec(vector <string> expr) { return accumulate(expr.begin(),expr.end(),string("")); }
	int count(vector <string> s1000, vector <string> s100, vector <string> s10, vector <string> s1, vector <string> t1000, vector <string> t100, vector <string> t10, vector <string> t1) {
		
		string S1000=concatvec(s1000),S100=concatvec(s100),S10=concatvec(s10),S1=concatvec(s1);
		string T1000=concatvec(t1000),T100=concatvec(t100),T10=concatvec(t10),T1=concatvec(t1);
		S.clear();
		N=S1000.size();
		
		int i,j,mint=9999,ret=0;
		FOR(i,N) {
			S.push_back(make_pair((S1000[i]-'0')*1000+(S100[i]-'0')*100+(S10[i]-'0')*10+(S1[i]-'0'),
				(T1000[i]-'0')*1000+(T100[i]-'0')*100+(T10[i]-'0')*10+(T1[i]-'0')));
			mint = min(mint,S[i].second);
		}
		
		sort(S.begin(),S.end());
			
		FOR(i,N) {
			int cmt = mint;
			int j = 0;
			while(j<N) {
				if(S[i].first <= cmt) cmt=max(cmt,S[i].second);
				int nt=cmt;
				
				while(j<N && S[j].first <= cmt) {
					nt=max(nt,S[j].second);
					j++;
				}
				if(j==N) break;
				if(nt==cmt) return -1;
				cmt=nt;
				ret++;
			}
		}
		return ret;
	}
};

まとめ

本番はi番目の人からどうやって左右に自己紹介を広げていこう、と考えてうまくいかなかった。
それにしてもこの問題、入力形式が珍しいな。