SRM 595 DIV1 本番

朝のSRM。少し眠くて心配だったが緊張で眠気は吹き飛んだ。

Coding

900がMedより簡単なこと稀にあるよなーとか考え、Medより前に900を開こうと考えた。

Easy (250)

最初に、「2^(他の[L[j],R[j] ]に被覆されないiの数)?」と考えた。実際にはこれは合っていた。
しかしどうもそれが納得できなくて、罠ありそうだなーと考えてしまった。
次に「同じ色で塗らないといけないセルをまとめて、そのグループの数を数えればいい?」とおもった。
これはUnionFind(無駄に動的)でやった。
何も塗られない場所のグループは1、それ以外は2を答えに掛け算する。
結構テストして、心配ながらも提出。

Hard (900)

まず期待値といえば期待値の線形性だよな、と考えた。
それには凸包を分解する。三角形分解を考えて、それを足せばいいんじゃないか?と思った。
しかし肝心の「この三角形が凸包の三角形分解」になる確率がわからず、さらにそれは重複して数えてしまうことに気づいた。
そしてわからなくなった。Mediumが時間かかるもので解けないとだめだと思い、あきらめてMediumへ。

Medium (500)

とりあえず左右を別個に「left[i][j] = 区間[i,j)で右側の連続するG(途中でminGreen個以上出てるならminGreenで固定)」と「right[i][j] = 区間[i,j)で左側の連続するG(同上)」というように2つ計算すればいいと、割と素直に考えられた。
これの計算は普通に区間を拡張してく感じで計算してけばいい。
さて、左と右を組み合わせなければいけない。
左の区間を[i,j]とすると、この区間に対応できる右の区間は{ [k,l) | j <= k, right[k][l] >= minGreen - left[i][j] }となる。これを高速に数えるにはどうしたらいいだろうか?
この答えも素直に思いつけた。Fenwick木を動的に使えばいい。tをFenwick木とする。
jを右端から左へ移動させる。ループ中では全てのlに対してtのright[j][l]の位置をインクリメントする。
その後各i,jに対してtの[minGreen - left[i][j],∞)のsumを求めればよい。このsumが答えとなる。
テストを何回かした。その時システムが不調でテストに時間がかかって、それで30ptくらい減った。しかしテストは重要なので良い。落ちたら0点なのだから、数十点で一喜一憂してはいけない。

Challenge

4人落とされてたけど、読んでもなんで落ちたのかわからなかった。その程度のChallenge力。これは改善すべき。

SystemTest

通ってよかった。

結果

Easy: 204.51 / 250
Medium: 379.92 / 500
Hard: Opened / 900
Challenge: 0/0 = +0
Division Place: 23/455
Rating: 18201957

コメント

練習を続けよう。Challenge練習もしたいところ。
今回はMediumを速く解けたのでよかったけれど、Hardを先に開くのはやはり自分には少し早い気もする。やめよう。

コード

謎コード

Easy
#include <vector>
#define rep(i,n) for(int (i)=0;(i)<(int)(n);++(i))
#define rer(i,l,u) for(int (i)=(int)(l);(i)<=(int)(u);++(i))
using namespace std;
typedef long long ll;   
struct UnionFind {
	vector<int> data;
	UnionFind(int size_) : data(size_, -1) { }
	bool unionSet(int x, int y) {
		x = root(x); y = root(y);
		if (x != y) {
			if (data[y] < data[x]) swap(x, y);
			data[x] += data[y]; data[y] = x;
		}
		return x != y;
	}
	bool findSet(int x, int y) { return root(x) == root(y); }
	int root(int x) { return data[x] < 0 ? x : data[x] = root(data[x]); }
	int size(int x) { return -data[root(x)]; }
};

struct LittleElephantAndIntervalsDiv1 {
	long long getNumber(int M, vector <int> L, vector <int> R) {
		int n = L.size();
		UnionFind uf(M+1);
		rer(p, 1, M) {
			bool white = true;
			rep(i, n) white &= !(L[i] <= p && p <= R[i]);
			if(white) uf.unionSet(0, p);
		}
		rer(p, 1, M) rer(q, 1, M) {
			bool b = true;
			rep(i, n) {
				bool x = L[i] <= p && p <= R[i], y = L[i] <= q && q <= R[i];
				if(x && y)
					b = true;
				if(x ^ y)
					b = false;
			}
			if(b) uf.unionSet(p, q);
		}
		ll r = 1;
		rer(p, 0, M) if(uf.root(p) == p) {
			if(uf.findSet(p, 0)) r *= 1;
			else r *= 2;
		}
		return r;
	}
};
Medium
#include <string>
#include <vector>
#include <cstring>
#define rep(i,n) for(int (i)=0;(i)<(int)(n);++(i))
#define rer(i,l,u) for(int (i)=(int)(l);(i)<=(int)(u);++(i))
#define each(it,o) for(auto it = (o).begin(); it != (o).end(); ++ it)
#define mset(m,v) memset(m,v,sizeof(m))
using namespace std;
typedef long long ll;

struct FenwickTree {
	typedef ll T;
	vector<T> v;
	FenwickTree(int n): v(n, 0) {}
	void add(int i, T x) {
		for(; i < v.size(); i |= i+1) v[i] += x;
	}
	T sum(int i) {	//[0, i)
		T r = 0;
		for(-- i; i >= 0; i = (i & (i+1)) - 1) r += v[i];
		return r;
	}
	T sum(int left, int right) {	//[left, right)
		return sum(right) - sum(left);
	}
};

struct LittleElephantAndRGB {
	long long getNumber(vector <string> list_, int minGreen) {
		string s;
		each(i, list_) s += *i;
		int n = s.size();
		static short dpleft[2501][2501], dpright[2501][2501];
		mset(dpleft, 0);
		rep(i, n) {
			dpleft[i][i] = 0;
			rer(j, i+1, n) {
				int x = dpleft[i][j-1];
				if(x == minGreen) dpleft[i][j] = minGreen;
				else if(s[j-1] == 'G') dpleft[i][j] = x + 1 >= minGreen ? minGreen : x + 1;
				else dpleft[i][j] = 0;
			}
		}
		mset(dpright, 0);
		rer(j, 1, n) {
			dpright[j][j] = 0;
			for(int i = j-1; i >= 0; i --) {
				int x = dpright[i+1][j];
				if(x == minGreen) dpright[i][j] = minGreen;
				else if(s[i] == 'G') dpright[i][j] = x + 1 >= minGreen ? minGreen : x + 1;
				else dpright[i][j] = 0;
			}
		}
		FenwickTree t(minGreen+1);
		ll r = 0;
		for(int j = n; j >= 1; j --) {
			rer(l, j+1, n) t.add(dpright[j][l], 1);
			rep(i, j) {
				int x = dpleft[i][j];
				r += t.sum(minGreen - x, minGreen+1);	//j <= l, dpright[l][k] >= minGreen - x
			}
		}
		return r;
	}
};