ARC095

https://beta.atcoder.jp/contests/arc095

こいついっつも同じような記事書いてるな。

C
はい。
D
C(a,b) < C(c,b)(a < c)です。
E
列と行の操作は入れ替えることができます。なので行を全探索した後、点対称にできるかどうか列を見ればよいです。
いえば簡単ですがめちゃくちゃバグりやすいです。罠がたくさんあって結局通せなかった…
グラフっぽく言い換えると少しはマシになるかも。
if文もなるべく使わずにしてコンパクトにしたのがこれです。

int H, W;
char S[12][12];
pi P[12];
bool visited[12];
bool same[12][12];

int creek(int v) {
	visited[v] = true;
	int res = 1;
	rep(i, 0, W) {
		if(!visited[i] && same[v][i]) {
			res += creek(i);
		}
	}
	return res;
}

bool ok() {
	// debug(vector<pi>(P, P + (H + 1) / 2));
	char T[12][12];
	int m1 = (H - 1) / 2, m2 = H / 2;
	rep(i, 0, (H + 1) / 2) {
		int a = P[i].fst, b = P[i].sec;
		rep(j, 0, W) {
			T[m1 - i][j] = S[a][j];
			T[m2 + i][j] = S[b][j];
		}
	}

	bool self[12];
	memset(same, 0, sizeof(same));
	memset(visited, 0, sizeof(visited));
	memset(self, 0, sizeof(self));

	rep(i, 0, W) {
		rep(j, 0, W) {
			bool ok = true;
			rep(k, 0, H) {
				if(T[H - k - 1][i] != T[k][j]) {
					ok = false;
					break;
				}
			}
			same[i][j] = ok;
		}
	}
	// rep(i, 0, W) {
	// 	rep(j, 0, W) {
	// 		cout << same[i][j];
	// 	}
	// 	cout << "\n";
	// }
	rep(i, 0, W) {
		if(same[i][i]) self[i] = true;
	}
	rep(i, 0, W) {
		if(self[i] || visited[i]) continue;
		if(creek(i) % 2) return false;
	}
	int odd = 0;
	rep(i, 0, W) {
		if(visited[i]) continue;
		odd += creek(i) % 2;
	}
	return odd <= 1;
}


bool used[12];

bool loop(int k) {
	if(k == (H + 1) / 2) {
		if(ok()) return true;
		else return false;
	}
	if(H % 2 == 1 && k == 0) {
		bool res = false;
		rep(i, 0, H) {
			P[k] = pi(i, i);
			used[i] = true;
			res |= loop(k + 1);
			used[i] = false;
		}
		return res;
	}
	bool res = false;
	int at = -1;
	rep(i, 0, H) {
		if(used[i]) continue;
		at = i;
		break;
	}
	used[at] = true;
	rep(i, 0, H) {
		if(used[i]) continue;
		used[i] = true;
		P[k] = pi(at, i);
		res |= loop(k + 1);
		used[i] = false;
	}
	used[at] = false;
	return res;
}

void solve() {
	cin >> H >> W;
	rep(i, 0, H) {
		rep(j, 0, W) {
			cin >> S[i][j];
		}
	}
	if(loop(0)) cout << "YES\n";
	else cout << "NO\n";
}
 

CSAcademy: Round #76

つら。

ABC
はい。

D
あーもうめちゃくちゃだよ。
queueっぽいものが見えてから発想が転換できなかったのが敗因。
やっぱり実装力ないし、考察時に実装量を見積もるのも下手ですね。
面倒な問題たくさん解いて精進したほうが良さそう…

int N, M;
ll Y[MAX_N], X[MAX_N];
vector<ll> vec;
vector<pl> Q[MAX_N];
ll leftv[MAX_N], rightv[MAX_N];

int fd(ll v) {
	return lower_bound(all(vec), v) - vec.begin();
}

void pre(ll value[MAX_N]) {
	vec.clear();
	rep(i, 0, N) {
		vec.pb(X[i] - Y[i]);
		vec.pb(X[i] + Y[i]);
		vec.pb(X[i]);
	}
	sort(all(vec));
	vec.erase(unique(all(vec)), vec.end());
	M = sz(vec);
	rep(i, 0, M) {
		Q[i].clear();
	}
	rep(i, 0, N) {
		int at1 = fd(X[i]);
		int at2 = fd(X[i] - Y[i]);
		Q[at1].pb(pl(X[i] - Y[i], i));
		Q[at2].pb(pl(X[i] - Y[i], i));
	}
	set<pl> que;
	rep(i, 0, M - 1) {
		rep(j, 0, sz(Q[i])) {
			pl x = Q[i][j];
			if(que.find(x) != que.end()) {
				que.erase(x);
			}
			else {
				que.insert(x);
			}
		}
		if(que.empty()) {
			value[i] = linf;
		}
		else value[i] = (*que.begin()).fst;
	}
}

void solve() {
	cin >> N;
	rep(i, 0, N) {
		cin >> Y[i] >> X[i];
		X[i] *= -1;
	}
	pre(rightv);
	rep(i, 0, M - 1) {
		rightv[i] *= -1;
	}
	reverse(rightv, rightv + M);
	rep(i, 0, N) X[i] *= -1;
	pre(leftv);

	ll res = 0;
	// debug(vec);
	// debug(vl(leftv, leftv + M));
	// debug(vl(rightv, rightv + M));
	rep(i, 0, M - 1) {
		ll x1 = vec[i], x2 = vec[i + 1];
		ll l1 = x1 - leftv[i], l2 = x2 - leftv[i];
		ll r1 = rightv[i + 1] - x1, r2 = rightv[i + 1] - x2;
		// debug(i, x1, x2, l1, l2, r1, r2);
		ll X = x2 - x1;
		if(l1 < -linf / 2 && r1 < -linf / 2) continue;
		if(l1 >= r1) {
			ll l = l1 + X - 1;
			res += (l + l1) * X / 2;
		}
		else if(l2 <= r2) {
			ll r = r1 - (X - 1);
			res += (r + r1) * X / 2;
		}
		else {
			ll u = (r1 - l1) / 2;
			ll ul = r1 - u;
			ll ur = l1 + (u + 1);
			// debug(u, ul, ur);
			res += (u + 1) * (r1 + ul) / 2;
			res += (X - u - 1) * (l2 - 1 + ur) / 2;
		}
		// debug(res);
	}
	cout << res << "\n";
}

一応queueの解法でも通ったんで。でも上位陣の方々と比べると実装が遥かに複雑になってしまってるのが解ると思います。

E
mincutでしょって思ってたんですがmincutで通るらしいですね。Writerの想定解は違いますが。

精進4/11

https://beta.atcoder.jp/contests/arc063/tasks/arc063_c 範囲求めて木の根から決めていけば良い。証明が少しあやふやで本番WAしたら自信無くして通せなさそう。
https://arc079.contest.atcoder.jp/tasks/arc079_d 丁寧丁寧丁寧にやったのでバグらせなかったけどうーん遅いなぁ。ループ内の値が2択になるのでDPすれば良い。
https://agc011.contest.atcoder.jp/tasks/agc011_c 二部グラフかどうか判定すれば良いんだけどそれをバグらせるという…

bool loop(int v, int k) {
	used[v] = true;
	bi[v] = k;
	bool ok = true;
	rep(i, 0, sz(G[v])) {
		int n = G[v][i];
		if(!used[n]) {
			if(!loop(n, 1 - k)) {
				ok = false; // don't return false
			}
		}
		else {
			if(bi[v] == bi[n]) ok = false;
		}
	}
	return ok;
}

ちゃんと全部の連結成分についてvisitしないといけません。途中でfalseをreturnするとバグります。

精進4/8

https://arc061.contest.atcoder.jp/tasks/arc061_c dijkstraを工夫しようと思って失敗した。グラフの方を工夫しましょう。
https://arc066.contest.atcoder.jp/tasks/arc066_b これ通せたのは成長感じる。桁DPなんですが、背反+遷移をちゃんと意識して解けたので良かった。
https://arc079.contest.atcoder.jp/tasks/arc079_c N=50程度なのでaが大きい場合は工夫して、aが小さい時は愚直にやればいいと思ったんですが1CaseだけWA出てる…。和のmodが普遍みたいなmodが必要十分になることが多いので注意。

ARC094

https://beta.atcoder.jp/contests/arc094

惨敗でした。

C
えーわかんないのでDPした。
D
C(C+1)>=ABの式は出たんですが、方針が悪く詰めきることができず…
解説放送の二分探索のほうがわかりやすそう。
E
一回目の提出が1byte差で落ちたんですが、そこから冷静に直せたのは良かった。
でもやっぱり遅いよなぁ
F
どうせまた変な必要十分条件があるんやろと思ったらそうでした。しかし思いつかず。必要十分考えるとき和を見るのは大事っすね。

CSA Round#75

https://csacademy.com/contest/round-75

初参加です。

A
はい。
B
変なdfsした
C
sort and lower_bound
D
priority_queue
E
平方分割でmodが小さい時はsegtreeで愚直に、大きい時は二分探索と思ったんですが通らず…。
F
NTTやるんですが、式変形だけ書いておきます。

f(i)=(N-i+1)!Σ(k=i-1...N)[(k-1)/2](k-2)!/(k-i+1)!
=(N-i+1)!Σ(u=0...N-i+1)[(u+i-2)/2](u+i-3)!/u!
<=>f(N-1-l)=l!Σ(u=0...l)[(N-1+u-l)/2](N-2+u-l)!/u!
=l!Σ(u=0...l)F(u)G(l-u)
ただしF(i)=1/i!,G(i)=[(N-1-i)/2](N-2-i)!
となってNTTの式に変換できました。

精進4/4

実は引っ越しして一人暮らし始めたんですが、今日になってやっとwifi環境を用意出来たので、精進再開です。

http://codeforces.com/contest/959/problem/C 真ん中に2つ点がある木と、rootに全ての点が隣接している木を出力する。
http://codeforces.com/contest/959/problem/D エラトステネスの篩的なことをやる
http://codeforces.com/contest/959/problem/E 数式めんどい
http://codeforces.com/contest/959/problem/F 面白い。置換群のお話。集合Sの要素xについてx^aがSに属さなければ全てのxについてx^aがSに属さない。逆にあるxについてx^aがSに属せば全てのxについて成り立つ。これを使って愚直DPを高速化する。
https://beta.atcoder.jp/contests/arc085/tasks/arc085_b これも面白い。DPかなと思ったら全然違った。初手全取りすればコストはもちろんabs(W-An)、1つ残しはabs(An-1-An)となる。2つ以上残すのは実は意味がない。なぜなら後手は必ず値をabs(An-1-An)以下にできるからだ。
https://apc001.contest.atcoder.jp/tasks/apc001_d n要素の次数列がn頂点の木をなす<=>全ての次数が0以上であり和が2n-2であるを利用すれば簡単。
https://code-thanks-festival-2017-open.contest.atcoder.jp/tasks/code_thanks_festival_2017_g 脳内AC。半分全列挙
https://arc092.contest.atcoder.jp/tasks/arc092_b これ500じゃないよなぁ…bitの桁ごとに見るとlower_boundでまとめられることに気づく。