Hatena::Grouptopcoder

kojingharangの日記 RSSフィード

|

2012-04-11

SRM Div2 500 ImportantSequence

23:07 |  SRM Div2 500 ImportantSequence - kojingharangの日記 を含むブックマーク はてなブックマーク -  SRM Div2 500 ImportantSequence - kojingharangの日記  SRM Div2 500 ImportantSequence - kojingharangの日記 のブックマークコメント

B[N], OP('-'か'+')[N] が与えられて、A[i] OP[i] A[i+1] = B[i], A[i]>0 であるとき、A[0]~A[N] として可能な値の組み合わせはいくつあるか答える問題。無限にあるなら -1 を返す。

  • A[0] が決まると全ての A[i] が決まる。
  • なので、式 A[i] > 0 を A[0] '>'|'<' v に変換する。v と演算子によって A[0] の上限と下限が決まる。
  • 上限か下限が無い場合、解は無限にあるので -1 をかえす
  • max(0, 上限 - 下限+1) が答え。
  • 0 と max とってなくて死亡....

↓ (passed in practice room)

// PII, VI の定義を変えて ll を使うようにしてある
class ImportantSequence {
	public:
	PII f(int i, int op, ll v, vector <int>& B, string& OP) {
		if(i==0) return MP(op, v);
		op *= OP[i-1]=='-' ? 1 : -1;
		v *= (ll)(OP[i-1]=='-' ? 1 : -1);
		v += (ll)B[i-1];
		return f(i-1, op, v, B, OP);
	}
	int getCount(vector <int> B, string OP) {
		VI lb, ub;
		REP(i, B.size()+1) {
			PII p = f(i, 1, 0, B, OP);
			if(p.first== 1) lb.PB(p.second);
			if(p.first==-1) ub.PB(p.second);
		}
		//cout<<lb<<endl;
		if(lb.size()==0 || ub.size()==0) return -1;
		ll l = *max_element(ALL(lb));
		ll u = *min_element(ALL(ub));
		//cout<<l<<endl;
		//cout<<u<<endl;
		//return (u-1)-(l+1)+1; // NG!
		return max((ll)0, (u-1)-(l+1)+1);
	}
};

2012-04-09

VK Cup 2012 Round 3 (Unofficial Div. 2 Edition)

19:28 |  VK Cup 2012 Round 3 (Unofficial Div. 2 Edition)  - kojingharangの日記 を含むブックマーク はてなブックマーク -  VK Cup 2012 Round 3 (Unofficial Div. 2 Edition)  - kojingharangの日記  VK Cup 2012 Round 3 (Unofficial Div. 2 Edition)  - kojingharangの日記 のブックマークコメント

ooo-- +-0 (Rank 51) 1640->1653

Round 3 と同時開催の Div2。

日本の上位陣スゲェと思いながらsystem testを見てた。

174 C. Range Increments

19:28 |  174 C. Range Increments - kojingharangの日記 を含むブックマーク はてなブックマーク -  174 C. Range Increments - kojingharangの日記  174 C. Range Increments - kojingharangの日記 のブックマークコメント

  • 0-10^5の数字が1-10^5個入った配列が与えられる。全部 0 の状態から始めて与えられた配列にするには、L番目の数からR番目の数を +1 する操作を最低何回すればいいか。
  • 苦手な雰囲気がぷんぷんする
  • 最大値が連続してるとこを削ってく方法だと、最大値 M, 個数 N として O(NM) かかるのでだめ
  • なんかスタックを使って O(N) でできる雰囲気がする
  • 左から見て行って、topの値より大きかったら push, 小さかったら top が表す区間が終わるので pop すると同時に (L, R) と呼ぶ回数を記録する
  • スタックに入れる値としては、区間の高さと始まりの位置でよさそう
  • ならしコストを考えると push した分しか pop しないので O(N)
  • push するときの始まりの位置は、最後に pop した区間の始まりの位置と同じにするとかいうあたりが面倒
  • なんかぐちゃぐちゃしてて怪しい
  • どっかミスっててもおかしくないけど通った
int main() {
	int N;
	cin>>N;
	vector<PII> st(100010);
	vector<pair<PII, int> > ans(100010);
	int ansp=0;
	int anscount=0;
	int stp=0;
	REP(i, N) {
		int v;
		cin>>v;
		int push_pos=i;
		while(stp>0 && st[stp-1].second > v) {
			push_pos = st[stp-1].first;
			//cout<<"push_pos "<<push_pos<<endl;
			int prevH = max(v, stp-1>0 ? st[stp-2].second : 0);
			ans[ansp++] = MP(MP(st[stp-1].first+1, i), st[stp-1].second - prevH);
			anscount += st[stp-1].second - prevH;
			stp--;
		}
		if(stp==0) {
			if(v>0) st[stp++] = MP(push_pos, v);
		} else if(st[stp-1].second < v) {
			st[stp++] = MP(push_pos, v);
		}
		//REP(m, stp) cout<<st[m]<<" "; cout<<endl;
	}
	while(stp>0) {
		int prevH = stp-1>0 ? st[stp-2].second : 0;
		ans[ansp++] = MP(MP(st[stp-1].first+1, N), st[stp-1].second-prevH);
		anscount += st[stp-1].second-prevH;
		stp--;
	}
	
	cout<<anscount<<endl;
	REP(i, ansp) {
		REP(j, ans[i].second) {
			cout<<ans[i].first.first<<" "<<ans[i].first.second<<endl;
		}
	}
	
	return 0;
}

2012-04-08

TCO 2012 Round1B

22:55 |  TCO 2012 Round1B - kojingharangの日記 を含むブックマーク はてなブックマーク -  TCO 2012 Round1B - kojingharangの日記  TCO 2012 Round1B - kojingharangの日記 のブックマークコメント

xx- +-0 (Rank 1???) 1244->1153

夜更かししたのに0で残念。

250 FoxAndKgram

22:55 |  250 FoxAndKgram - kojingharangの日記 を含むブックマーク はてなブックマーク -  250 FoxAndKgram - kojingharangの日記  250 FoxAndKgram - kojingharangの日記 のブックマークコメント

  • 全部使うと勘違い
  • 再提出
  • kの最大値101なのに60からデクリメントスタート→と思ったけどrowがk個以上できないといけないから最大値は50でいいんですね
  • rowがちょうどk個できると勘違い

↓修正版(test pass in practice room)

class FoxAndKgram {
	public:
	int maxK(vector <int> len) {
		int N=len.size();
		for(int k=50;k>=0;k--) {
			VI used(N);
			int ok=1;
			int L=0;
			//cout<<k<<endl;
			REP(i, N) {
				if(used[i]) continue;
				if(len[i]==k) {used[i]=1;L++;continue;}
				REP(j, N) {
					if(used[j]||i==j) continue;
					if(len[i]+len[j]+1==k) {used[i]=used[j]=1;L++;break;}
				}
			}
			ok &= L>=k;
			//cout<<ok<<endl;
			if(ok) return k;
		}
		return 0;
	}
};

500 FoxAndDoraemon

22:55 |  500 FoxAndDoraemon - kojingharangの日記 を含むブックマーク はてなブックマーク -  500 FoxAndDoraemon - kojingharangの日記  500 FoxAndDoraemon - kojingharangの日記 のブックマークコメント

  • i番目以降のtaskを処理する最短時間というDPでやろうとしてうまくいかないことに気づく
  • 範囲にしないといかん
  • 連鎖行列積の問題みたく [begin, end) を使った最短時間をメモ化。
  • が!一箇所 max が min になってて WA
  • 最初全部 max にしててあれ最短だから min だ、あでもサブツリーの時間は長い方だ...とかいってるうちに直し漏れが生じた模様
  • (´Д`)
  • (2個と3個の場合の処理いらないし)

↓修正版(test pass in practice room)

vector <int> WC;
int SC;
int N;
map<PII, int> memo;
class FoxAndDoraemon {
	public:
	// [i0, i1)
	int f(int i0, int i1) {
		PII key=MP(i0, i1);
		if(memo.count(key)) return memo[key];
		int rest = i1-i0;
		if(rest<=0) return memo[key] = 0;
		if(rest==1) return memo[key] = WC[i0];
		if(rest==2) return memo[key] = SC+max(WC[i0], WC[i0+1]);
		if(rest==3) return memo[key] = SC+max(WC[i0], SC+max/*min*/(WC[i0+1], WC[i0+2]));
		// >=4
		int ans = 1000000;
		for(int i=1;i<rest;i++) {
			int c = SC+max(f(i0, i0+i), f(i0+i, i1));
			ans = min(ans, c);
		}
		return memo[key] = ans;
	}
	int minTime(vector <int> _WC, int _SC) {
		sort(ALLR(_WC));
		WC=_WC;
		SC=_SC;
		memo.clear();
		N=WC.size();
		int ans = f(0, N);
		return ans;
	}
};

2012-03-26

codeforces  VK Cup 2012 Round 2 (Unofficial Div. 2 Edition) 169 C. Substring and Subsequence

20:30 |  codeforces  VK Cup 2012 Round 2 (Unofficial Div. 2 Edition) 169 C. Substring and Subsequence - kojingharangの日記 を含むブックマーク はてなブックマーク -  codeforces  VK Cup 2012 Round 2 (Unofficial Div. 2 Edition) 169 C. Substring and Subsequence - kojingharangの日記  codeforces  VK Cup 2012 Round 2 (Unofficial Div. 2 Edition) 169 C. Substring and Subsequence - kojingharangの日記 のブックマークコメント

文字列sのsubstringと文字列tのsubsequenceが一致するようなものの個数を求める問題。長さはどちらも5000以内。

あとでできてる人のコードや解説を見て。

dp[i][j] = s[i]で終わるsubstringとt[j]以前の文字列のsubsequenceのうち内容が一致するものの個数

とすると、dp[i][j]はt[j]以前のsubsequenceのうちt[j]を使う場合と使わない場合に分けて考えることができる。

t[j]を使わない場合、使わないということはt[j-1]以前の文字列に対するsubsequenceなのでdp[i][j-1]を加算

t[j]を使う場合、s[i]とt[j]を両方使うことになる。

s[i]!=t[j]のときは前に何がきても一致しないので加算なし

s[i]==t[j]のときは s[i-1] でおわるsubstringとt[j-1]以前のsubsequenceが一致すればよいのでdp[i-1][j-1]、

それに加えてs[i]とt[j]一文字だけの場合があるのでさらに1を加算。

というわけで式は

dp[i][j] = dp[i][j-1] + (s[i]==t[j] ? 1+dp[i-1][j-1] : 0)

となる

答えはsubstringが終わるすべての位置について足せばいいのでΣi dp[i][t.size-1]

.....と、言われると納得するけど思いつかんのだなぁ。

本番中はs[i]以前のsubstringとt[j]以前のsubsequenceでずっと考えてて、なんか4通りあるしさらに重複してそうとなってできなかった。

しばらく考えてできないときは状態をもっと分割してみて最後に足す、というアプローチが使えるかも。

(↓あとで通したやつ)

#define MOD 1000000007LL

int main() {
	string A,B;
	cin>>A>>B;
	
	VVI dp(A.size()+1, VI(B.size()+1, 0));
	
	for(int i=1; i<A.size()+1; i++) for(int j=1; j<B.size()+1; j++) {
		dp[i][j] = ((ll)dp[i][j-1] + (A[i-1]==B[j-1] ? 1+dp[i-1][j-1]:0)) % MOD;
	}
	ll ans = 0;
	REP(i, A.size()+1) ans = (ans+dp[i][B.size()])%MOD;
	cout<<ans<<endl;
	
	return 0;
}

2012-03-25

Codeforces 166B Polygons

10:27 |  Codeforces 166B Polygons - kojingharangの日記 を含むブックマーク はてなブックマーク -  Codeforces 166B Polygons - kojingharangの日記  Codeforces 166B Polygons - kojingharangの日記 のブックマークコメント

  • A ポリゴンは convex, B ポリゴンはそうとは限らない。B が A の中にあるかどうかを求める問題。
  • A, Bの頂点数を N, M として N <= 10^5, M <= 2*10^4
  • B ポリゴンは単なる点の集合だと思って、X でソートしておく。
  • まず A の X 座標の範囲から外れる B の点があったら NG
  • A ポリゴンの各辺 e について、その辺の X の範囲にある B ポリゴンの点集合を2分探索で求めて...
  • e が +X 方向なら辺の下(-Y方向)、-X 方向なら辺の上(+Y方向)にあるかどうかを確認する。
  • 整数のまま条件判定しようとしたけど移項したら正負が変わっちゃうのでんーまぁいいやって double を使った
  • e が Y 座標に平行だったときはチェックしない
  • LessFoo は不要だったと思う
  • O(NlogM + M) くらい?

#define INF 2000000000

class LessFoo {
public:
	bool operator()(const PII& a, const PII& b) const {
		return a.first < b.first;
	}
};

int main() {
	int N, M;
	cin>>N;
	
	vector<PII> A(N);
	int Axmin=INF, Axmax=-INF;
	REP(i, N) {
		cin>>A[i].first>>A[i].second;
		Axmin=min(Axmin, A[i].first);
		Axmax=max(Axmax, A[i].first);
	}
	cin>>M;
	vector<PII> B(M);
	int xmin=INF, xmax=-INF;
	REP(i, M) {
		cin>>B[i].first>>B[i].second;
		xmin=min(xmin, B[i].first);
		xmax=max(xmax, B[i].first);
	}
	if(xmin <= Axmin || Axmax <= xmax) {
		cout<<"NO"<<endl;
		return 0;
	}
	sort(ALL(B));
	
	REP(i, N) {
		int x0 = A[i].first;
		int x1 = A[(i+1)%N].first;
		int y0 = A[i].second;
		int y1 = A[(i+1)%N].second;
		if(x0==x1) continue;
		int i0 = distance(B.begin(), lower_bound(ALL(B), MP(x0, -INF), LessFoo()));
		int i1 = distance(B.begin(), lower_bound(ALL(B), MP(x1, -INF), LessFoo()));
		//cout<<i<<"   "<<A[i].first<<" "<<A[(i+1)%N].first<<" "<<i0<<" "<<i1<<endl;
		
		for(int i=i0;i<i1;i++) {
			double x = B[i].first;
			double y = B[i].second;
			if(!( y < ((double)y1-y0)/(x1-x0)*(x-x0)+y0 )) {
				cout<<"NO"<<endl;
				return 0;
			}
		}
		for(int i=i1;i<i0;i++) {
			double x = B[i].first;
			double y = B[i].second;
			//cout<<x<<" "<<y<<endl;
			//cout<<x0<<" "<<y0<<endl;
			//cout<<x1<<" "<<y1<<endl;
			//cout<<(y - y0)<<" "<<(y1-y0)*(x-x0)<<endl;
			if(!( y > ((double)y1-y0)/(x1-x0)*(x-x0)+y0 )) {
				cout<<"NO"<<endl;
				return 0;
			}
		}
	}
	cout<<"YES"<<endl;
	
	return 0;
}
|