Hatena::Grouptopcoder

kojingharangの日記 RSSフィード

|

2013-07-27

SRM 586 Div1 250 PiecewiseLinearFunction

03:28 |  SRM 586 Div1 250 PiecewiseLinearFunction - kojingharangの日記 を含むブックマーク はてなブックマーク -  SRM 586 Div1 250 PiecewiseLinearFunction - kojingharangの日記  SRM 586 Div1 250 PiecewiseLinearFunction - kojingharangの日記 のブックマークコメント

  • (i, Y[i]) で表される折れ線グラフが与えられる。y=?? の直線と折れ線グラフとの交点の数の最大値を求める。
  • 1≦N≦50, -1,000,000,000≦Y[i]≦1,000,000,000
  • y 座標の区間に -1, +1 を対応させて、yが小さいほうから見ていってカウンタを増減させる line sweep な感じ
  • x 座標が共有される点の処理が面倒
  • ガチャガチャガチャ
  • failed system test

(あとで)

  • y, y±0.5で全通り調べるほうが簡潔だった。もう少し方針をちゃんと考えるべし。。
  • accepted in practice
class PiecewiseLinearFunction {
	public:
	int maximumSolutions(vector <int> Y) {
		REP(i, Y.size()) Y[i]*=2;
		int offset[] = {-1, 0, 1};
		ll ans = 0;
		REP(i, Y.size()) {
			REP(oi, 3) {
				ll y = Y[i]+offset[oi];
				ll cnt = 0;
				REP(i, Y.size()) if(Y[i]==y) cnt++;
				REP(i, Y.size()-1) {
					if(Y[i]==Y[i+1]) return -1;
					if(min(Y[i], Y[i+1])<y && y<max(Y[i], Y[i+1])) cnt++;
				}
				ans = max(ans, cnt);
			}
		}
		return ans;
	}
};

2013-07-20

SRM 585 Div1 250 TrafficCongestion

16:37 |  SRM 585 Div1 250 TrafficCongestion - kojingharangの日記 を含むブックマーク はてなブックマーク -  SRM 585 Div1 250 TrafficCongestion - kojingharangの日記  SRM 585 Div1 250 TrafficCongestion - kojingharangの日記 のブックマークコメント

  • 高さ TH の完全二分木がある。適当な2頂点を選んで2点間のエッジを塗る。
  • 1つのエッジは2回塗らないようにしたい。最低何回塗れば全エッジを塗れるか。
  • 1≦TH≦1,000,000
  • とりあえず長いのということで一番左の葉から一番右の葉まで塗ってみるも、結局余る点がちらほら出る
  • 分かりやすそうな塗り方ということで下から∧状に塗ってみる
  • (証明なしw)
  • accepted
class TrafficCongestion {
	public:
	int theMinCars(int TH) {
		ll ans = 1;
		REP(i, TH-1) ans = (2 * ans + (i%2==0 ? 1 : -1)) % 1000000007LL;
		return ans;
	}
};

↓ちなみに modulo の数をコピペしてもコンパイル通る(けど 0 か 1 しか返らない)のでややこしい。。

class TrafficCongestion {
	public:
	int theMinCars(int TH) {
		ll ans = 1;
		REP(i, TH-1) ans = (2 * ans + (i%2==0 ? 1 : -1)) % 1,000,000,007LL;
		return ans;
	}
};

SRM 585 Div1 500 LISNumber

16:00 |  SRM 585 Div1 500 LISNumber - kojingharangの日記 を含むブックマーク はてなブックマーク -  SRM 585 Div1 500 LISNumber - kojingharangの日記  SRM 585 Div1 500 LISNumber - kojingharangの日記 のブックマークコメント

  • 数字 i が CS[i] 個あるとき、それらを並び替えて最長部分増加列の個数が K 個になるようにしたい。何通りあるか求める問題。
  • 1≦N≦36, 1≦CS[i]≦36, 1≦K≦1296
  • dp[n][k] ... CS[i], i in [0, n) を使って k 個の LIS を作る方法の個数と置くのだろう
  • 更新は dp[n][k] = Σ(pk in [0, k]) dp[n-1][pk] * (LISの個数がpk個からk個になるようなnの挿入箇所が何通りあるか)
  • dp[N][K] が答え
  • どんなときに LIS の個数が増えるか?
  • 各 LIS の最後に n を置くと、LIS の個数は増えない(n-1までの数字しか置いてないので)。こういう場所は pk 個ある。
  • 新しく置く CS[n] 個の n のうち、CS[n]-(k-pk) 個はこれらの場所から選んで 1 コずつおけばいい。
  • なので Comb(pk, CS[n]-(k-pk)) 通り
  • それ以外の場所に複数個 n を挿入すると、LIS の個数は置いただけ増える. その中から k-pk 個重複ありで置く。
  • Homogeneous Product(いままで置いた数字の数+1 - pk, k-pk)
  • Homogeneous Product(N, K) == Combination(N+K-1, K) ... 区切りを置くと考えるやつ
  • としたがサンプル合わず→おわり
  • (あとで)
  • LIS の個数が増えないとこに置いたら、以降その場所は LIS の個数が増える場所に変わるのであった
  • 0 0 0 (LIS 3コ)
  • 0 0 0 1 (LIS 3コ)
  • 0 0 0 1 1 (LIS 4コ)
  • ということで LIS の個数が増えないとこに実際に置く数分だけ LIS の個数が増える場所を増やして
  • Homogeneous Product(いままで置いた数字の数+1 - (pk-(CS[n]-(k-pk))), k-pk)
  • としたら通った。
  • accepted in practice
#define MOD 1000000007LL
#define N_MAX 1300
#define K_MAX 1300
int comb[N_MAX][K_MAX];
ll combf(int n, int k) {
	if(!(0<=n && n<N_MAX)) return 0;
	if(!(0<=k && k<K_MAX)) return 0;
	return comb[n][k];
}

class LISNumber {
	public:
	int count(vector <int> CS, int K) {
		REP(n, N_MAX) comb[n][0] = 1;
		RANGE(n, 1, N_MAX) RANGE(m, 1, K_MAX) comb[n][m] = ((ll)comb[n-1][m-1] + comb[n-1][m]) % MOD;
		
		int N=CS.size();
		VVI dp(N+1, VI(K+1)); // dp[n][k] ... CS[i], i in [0, n) を使って k 個の LIS を作る方法の個数 % MOD
		dp[0][0] = 1;
		ll sum = 1;
		RANGE(i, 1, N+1) {
			RANGE(k, 1, K+1) {
				RANGE(pk, 0, k+1) {
					int add = k-pk; // in [0, k]
					int rest = CS[i-1] - add;
					ll plus = dp[i-1][pk] * combf(sum-(pk-rest)-1+add, add) % MOD * combf(pk, rest) % MOD;
					dp[i][k] += plus;
					dp[i][k] %= MOD;
				}
			}
			sum += CS[i-1];
		}
		return dp[N][K];
	}
};

2013-07-10

SRM 584 Div1 250 Egalitarianism

00:30 |  SRM 584 Div1 250 Egalitarianism - kojingharangの日記 を含むブックマーク はてなブックマーク -  SRM 584 Div1 250 Egalitarianism - kojingharangの日記  SRM 584 Div1 250 Egalitarianism - kojingharangの日記 のブックマークコメント

  • 友達関係が Y/N で与えられる。自分の所持金は友達の所持金±D以内じゃないといけない。人々の所持金の最大差を求める問題。
  • 人数≦50
  • ある人とある人が何ホップでつながってるか分かれば、そのホップ数 x D の最大値が答え。
  • Warshall-Floyd さん
  • accepted
class Egalitarianism {
	public:
	int maxDifference(vector <string> F, int D) {
		int N=F.size();
		ll INF = 1LL<<50;
		VVI w(N, VI(N, INF));
		REP(i, N) w[i][i] = 0;
		REP(i, N) REP(j, N) if(F[i][j]=='Y') w[i][j] = 1;
		REP(k, N) REP(i, N) REP(j, N) w[i][j]=min(w[i][j], w[i][k]+w[k][j]);
		ll d = 0;
		REP(i, N) REP(j, N) d=max(d, w[i][j]);
		return d==INF ? -1 : d*D;
	}
};

2013-06-18

SRM 583 Div1 500 TurnOnLamps

03:02 |  SRM 583 Div1 500 TurnOnLamps - kojingharangの日記 を含むブックマーク はてなブックマーク -  SRM 583 Div1 500 TurnOnLamps - kojingharangの日記  SRM 583 Div1 500 TurnOnLamps - kojingharangの日記 のブックマークコメント

  • 木が与えられる。各枝に値(0or1)と重要かどうか(0or1)がついてる。
  • 2つのノードを指定するとそれらの最短経路上の枝の値が反転する。これを最低何回やると重要な枝すべてを 1 にできるか。
  • 2≦ノード数≦50
  • ... 木の理論(?)とか分かんないし

  • 全探索を考える
  • ノード2つを決めると、反転する枝の番号リストが決まる。このリストを long long に入れる
  • 初期値 bS と重要ラベル bG も long longに入れる
  • 初期値から遷移していって (bS&bG)==bG になったら終わり
  • 目的の状態に近づかないものは探索しなくていいだろう
  • BFSでやってたけどあれってなってDijkstraに書き換え

  • 被撃墜(OOF)

(あとで)

  • 答えが 0 になるときの処理をしてなかった。もったいなし(´・ω・`)
  • (もっと賢い簡潔な方法があるはずである)
  • ↓passed in practice room
// 0 is good
ll f(ll a, ll g) {
	return POPCOUNTLL(g)-POPCOUNTLL(a&g);
}

struct p3 {
	ll po, no, cost;
	bool operator<(const p3& b) const {
		return po<b.po;
	}
};

class TurnOnLamps {
	public:
	int minimize(vector <int> R, string S, string G) {
		int N=R.size()+1;
		VI w;
		REP(i, N) REP(j, N) {
			if(i==j) continue;
			VI p0, p1;
			{
				int nid = i;
				while(nid) {
					p0.PB(nid-1);
					nid = R[nid-1];
				}
			}
			{
				int nid = j;
				while(nid) {
					p1.PB(nid-1);
					nid = R[nid-1];
				}
			}
			reverse(ALL(p0));
			reverse(ALL(p1));
			int k=0;
			while(k<p0.size() && k<p1.size() && p0[k]==p1[k]) k++;
			ll ww=0;
			RANGE(l, k, p0.size()) ww|=1LL<<p0[l];
			RANGE(l, k, p1.size()) ww|=1LL<<p1[l];
			w.PB(ww);
		}
		//cout<<w<<endl;
		ll bS = 0;
		REP(i, S.size()) if(S[i]=='1') bS|=1LL<<i;
		ll bG = 0;
		REP(i, G.size()) if(G[i]=='1') bG|=1LL<<i;
		
		if((bS & bG)==bG) return 0;     // これ!!
		
		priority_queue<p3> q;
		q.push((p3){-f(bS, bG), bS, 0});
		while(q.size()) {
			ll po = -q.top().po;
			ll no = q.top().no;
			ll cost = q.top().cost;
			q.pop();
			REP(i, w.size()) {
				ll nno = no ^ w[i];
				if((nno & bG)==bG) return cost+1;
				ll npo = f(nno, bG);
				if(npo < po) {
					q.push((p3){-npo, nno, cost+1});
				}
			}
		}
		return -1;
	}
};

2013-06-04

SRM 581 Div1 250 SurveillanceSystem (追記)

23:03 |  SRM 581 Div1 250 SurveillanceSystem (追記) - kojingharangの日記 を含むブックマーク はてなブックマーク -  SRM 581 Div1 250 SurveillanceSystem (追記) - kojingharangの日記  SRM 581 Div1 250 SurveillanceSystem (追記) - kojingharangの日記 のブックマークコメント

  • 連続した N 個の区画があって各区画に荷物が最大 1 個入っている。
  • 連続した L 個の区画を監視できるカメラがいくつかあって、各カメラが観測した荷物の個数が与えられる。
  • 各カメラが監視する範囲は重複しない。
  • 各区画について、確実に監視されているなら '+', 確実に監視されていないなら '-', 監視されている可能性があるなら '?', のどれかを求める問題。
  • N≦50, 1≦L≦N
  • カメラが観測した箱の数→その個数 と集計しておく
  • 観測した数が異なればその候補の区間も異なるので、観測した箱の数ごとに独立に考える。
  • 候補の区間全てについて区間に含まれる箱のとこを+1していくと、...
  • ある箱が何回使われたか分かる。
  • カメラの個数>カメラの位置候補数-箱が使われた回数 なら、その箱を避けることはできないので + にする。
  • そうでなくて1回でも使われてたら - だった場合に限り ? にする。
X---X-- {2,2} L=3の場合
1コのカメラの置き方の候補は4通り
ooo----
--ooo--
---ooo-
----ooo
1122321

(Naiveなやり方)
実際には{2,2}なので2コのカメラを置く必要がある。
置き方は4C2通り
ooooo--
oooooo-
ooo-ooo
--oooo-
--ooooo
---oooo
結果
????+??

...なんだけど、上記の方法だと40C20通りとかになる場合があって終わらない。

(工夫すると)
1コのカメラの置き方の候補からなんとかする。
ooo----
--ooo--
---ooo-
----ooo
1122321

4通りから異なる2個を選べばいい
→どう選んでも3のとこは1個以上のカメラに使われる=監視されるので +
→2以下のとこは適切な選び方をすると監視されるようにもされないようにできるので ?
なので
????+??
みたいな
  • accepted
  • ↓簡潔にした版(passed in practice room)
class SurveillanceSystem {
	public:
	string getContainerInfo(string C, vector <int> R, int L) {
		map<int, int> hi;
		int N=C.size();
		string ans(N, '-');
		REP(i, R.size()) hi[R[i]]++;
		FOR(e, hi) {
			int match=0;
			VI w(N);
			REP(i, N-L+1) {
				if(count(&C[i], &C[i+L], 'X')==e->first) {
					match++;
					REP(j, L) w[i+j]++;
				}
			}
			REP(i, N) {
				if(w[i]>=match-(e->second-1)) ans[i]='+';
				else if(w[i]>0 && ans[i]!='+') ans[i]='?';
			}
		}
		return ans;
	}
};
|