Hatena::Grouptopcoder

kojingharangの日記 RSSフィード

|

2012-05-06

GCJ2012 Round1B

14:37 |  GCJ2012 Round1B - kojingharangの日記 を含むブックマーク はてなブックマーク -  GCJ2012 Round1B - kojingharangの日記  GCJ2012 Round1B - kojingharangの日記 のブックマークコメント

  • びーる&深夜で過酷だったけど rank 844 でなんとか通過予定
  • 問題 B が 1.5h あったのにできなかったのは問題であるなぁ

GCJ2012 Round1B A. Safety in Numbers

14:37 |  GCJ2012 Round1B A. Safety in Numbers - kojingharangの日記 を含むブックマーク はてなブックマーク -  GCJ2012 Round1B A. Safety in Numbers - kojingharangの日記  GCJ2012 Round1B A. Safety in Numbers - kojingharangの日記 のブックマークコメント

  • S[i] が与えられる。0<=Y[i]<=1 として、各 i について F[i] = S[i]+(ΣS)*Y[i] が単独で最小にならないようにするための Y[i] の最小値を求める問題。
  • Y[i] が決まると F[i] が決まって、i!=j な F[j] が F[i] 以下になればいいので
  • Y[j] として最低必要な分を 1-Y[i] から補充していく。
  • 全部補充できたら F[i] は単独で最小にならない。
  • 各 i について Y[i] を 0~1 の間で二分探索する。
  • max(0, A-w[j]) の和 < 1-Y[i] かどうかだけ判定したほうがスマートだった
int f(int i, double mid, VI& w, int N, int sum) {
	double A = w[i]+sum*mid;
	double rest = sum*(1-mid);
	int ok=1;
	REP(j, N) {
		if(i==j) continue;
		if(A>w[j]) {
			rest -= A-w[j];
			if(rest<0) {
				ok=0;
				break;
			}
		}
	}
	return ok;
}

int main() {
	int test_cases;
	cin>>test_cases;
	REP(ttt, test_cases) {
		int N;
		cin>>N;
		VI w(N);
		REP(i, N) cin>>w[i];
		int sum = accumulate(ALL(w), 0);
		
		cout<<"Case #"<<ttt+1<<": ";
		REP(i, N) {
			if(i!=0) cout<<" ";
			double lo = 0, hi = 1;
			REP(loop, 100) {
				double mid = (lo+hi)/2;
				//cout<<mid<<" "<<A<<" "<<ok<<endl;
				int ok = f(i, mid, w, N, sum);
				if(ok) lo=mid;
				else   hi=mid;
			}
			cout<<setprecision(8)<<hi*100;
		}
		cout<<endl;
	}
	return 0;
}

GCJ2012 Round1B B. Tide Goes In, Tide Goes Out

14:37 |  GCJ2012 Round1B B. Tide Goes In, Tide Goes Out - kojingharangの日記 を含むブックマーク はてなブックマーク -  GCJ2012 Round1B B. Tide Goes In, Tide Goes Out - kojingharangの日記  GCJ2012 Round1B B. Tide Goes In, Tide Goes Out - kojingharangの日記 のブックマークコメント

  • カヤックが W x H セルの洞窟にいて水が毎秒10cmで下がる。水位と各セルの地面と天井の高さによって隣のセルに進めるかどうか決まる(詳細省略...)ゴールまで行く最短時間を求める問題。
  • 右か下にしか進まないと思ってて、O(WH) の DP を書いた
  • 水位が下がらなくても進める時間はカウントしない処理を入れる
  • Small の実行結果を見ると INF になってるのがあっておかしい
  • そうか左に進むこともあるのか
  • BFS
  • WA
  • おわり

(あとで)

  • なるほど Dijkstra か..
  • deque を priority_queue に書き換える
  • priority_queue は大きいのから出てくるので時間を負にして push
  • AC
  • 各セルの水位も保存してるけど、水位は時刻から決まるから不要だった。いろいろ無駄に複雑に書いてしまった
#define INF 100000000

int main() {
	int test_cases;
	cin>>test_cases;
	REP(ttt, test_cases) {
		int L, H, W;
		cin>>L>>H>>W;
		VVI ce(H, VI(W));
		VVI fl(H, VI(W));
		REP(y, H) REP(x, W) cin>>ce[y][x];
		REP(y, H) REP(x, W) cin>>fl[y][x];
		VVI ti(H, VI(W, INF));
		VVI he(H, VI(W));
		VVI st(H, VI(W, 1));
		st[0][0] = 0;
		ti[0][0] = 0;
		he[0][0] = L;
		VVI vis(H, VI(W));
		priority_queue <pair <int, pair <int, int> > > q;
		//deque<PII> q;
		q.push(MP(0, MP(0,0))); // x, y
		int ok=0;
		while(q.size()) {
			int x = q.top().second.first;
			int y = q.top().second.second;
			//cout<<"pop "<<q.top().first<<"  "<<x<<" "<<y<<endl;
			q.pop();
			if(ti[y][x]==INF) continue;
			if(x==W-1 && y==H-1) {ok=1;break;}
			if(vis[y][x]) continue;
			vis[y][x]=1;
			int tdx[] = {1, 0, -1, 0};
			int tdy[] = {0, 1, 0, -1};
			REP(dir, 4) {
				if(dir==0 && x>=W-1) continue; // right
				if(dir==1 && y>=H-1) continue; // down
				if(dir==2 && 0>=x) continue; // left
				if(dir==3 && 0>=y) continue; // top
				int nx = x+tdx[dir];
				int ny = y+tdy[dir];
				int lvl = he[y][x];
				if(fl[y][x]+50<=ce[ny][nx] && fl[ny][nx]+50<=ce[ny][nx] && fl[ny][nx]+50<=ce[y][x] ) {
					int wait = max(0, lvl-(ce[ny][nx]-50));
					if(!st[y][x] && wait==0) {
						st[ny][nx] = 0;
						ti[ny][nx] = ti[y][x];
						he[ny][nx] = he[y][x];
					} else
					if(fl[y][x]+20<=lvl-wait) {
						if(ti[y][x]+wait+10 < ti[ny][nx]) {
							ti[ny][nx] = ti[y][x]+wait+10;
							he[ny][nx] = lvl-(wait+10);
						}
					} else {
						if(ti[y][x]+wait+100 < ti[ny][nx]) {
							ti[ny][nx] = ti[y][x]+wait+100;
							he[ny][nx] = lvl-(wait+100);
						}
					}
					//cout<<"push "<<ti[ny][nx]<<" "<<nx<<" "<<ny<<endl;
					q.push(MP(-ti[ny][nx], MP(nx, ny)));
				}
			}
			//cout<<"loop end"<<endl;
		}
		//cout<<ti<<endl;
		//cout<<he<<endl;
		//cout<<st<<endl;
		//if(!ok) cout<<"!!!!"<<endl;
		cout<<"Case #"<<ttt+1<<": "<<(double)ti[H-1][W-1]/10<<endl;
	}
	return 0;
}

GCJ2012 Round1B C. Equal Sums

14:37 |  GCJ2012 Round1B C. Equal Sums - kojingharangの日記 を含むブックマーク はてなブックマーク -  GCJ2012 Round1B C. Equal Sums - kojingharangの日記  GCJ2012 Round1B C. Equal Sums - kojingharangの日記 のブックマークコメント

  • いくつかの整数が与えられる。和が同じになる異なる部分集合を2つ見つける問題
  • small は部分集合とその和を全通り計算する
  • large は乱択らしい 解説待ち。
void pr(ll i, VI& w, int N) {
	int first=1;
	REP(j, N) {
		if((i>>j)&1) {
			if(!first) cout<<" ";
			cout<<w[j];
			first=0;
		}
	}
	cout<<endl;
}

int main() {
	int test_cases;
	cin>>test_cases;
	REP(ttt, test_cases) {
		int N;
		cin>>N;
		VI w(N);
		REP(i, N) cin>>w[i];
		map<ll, ll> ma;
		int sum = accumulate(ALL(w), 0);
		int ok=0;
		REP(i, ((ll)1)<<N) {
			int A = 0;
			REP(j, N) {
				if((i>>j)&1) A += w[j];
			}
			if(ma.count(A)) {
				cout<<"Case #"<<ttt+1<<":"<<endl;
				pr(ma[A], w, N);
				pr(i, w, N);
				ok=1;
				break;
			}
			ma[A] = i;
		}
		
		if(!ok) cout<<"Case #"<<ttt+1<<": Impossible"<<endl;
	}
	return 0;
}

2012-05-02

AtCoder Regular Contest #002

23:06 |  AtCoder Regular Contest #002 - kojingharangの日記 を含むブックマーク はてなブックマーク -  AtCoder Regular Contest #002 - kojingharangの日記  AtCoder Regular Contest #002 - kojingharangの日記 のブックマークコメント

  • 今回はさくさく動いてよかった
  • GCJ みたいに順位表の何ページ目を見てても自分の順位が表示されているとありがたいです

AtCoder 002, B 割り切れる日付

22:58 |  AtCoder 002, B 割り切れる日付 - kojingharangの日記 を含むブックマーク はてなブックマーク -  AtCoder 002, B 割り切れる日付 - kojingharangの日記  AtCoder 002, B 割り切れる日付 - kojingharangの日記 のブックマークコメント

ここからpython

import sys
import datetime

y,m,d = map(int, sys.stdin.readline().split("/"))
d=datetime.date(y,m,d)
while True:
	if d.year % d.month==0 and (d.year / d.month) % d.day==0:
		print "%04d/%02d/%02d" % (d.year, d.month, d.day)
		sys.exit(0)
	d = d + datetime.timedelta(1)

AtCoder 002, C コマンド入力

22:58 |  AtCoder 002, C コマンド入力 - kojingharangの日記 を含むブックマーク はてなブックマーク -  AtCoder 002, C コマンド入力 - kojingharangの日記  AtCoder 002, C コマンド入力 - kojingharangの日記 のブックマークコメント

流れでpython :)

datetime 要らんしw

import sys
import datetime

N=int(sys.stdin.readline())
s = sys.stdin.readline().rstrip()
if N==1:
	print 1
	sys.exit(0)

#print s

tt = [ x+y for x in "ABXY" for y in "ABXY" ]
#print tt


ans = 10000
for L in tt:
	for R in tt:
		ans = min(ans, len(s.replace(L, "L").replace(R, "R")))

print ans

2012-04-28

GCJ12 Round1A

02:01 |  GCJ12 Round1A  - kojingharangの日記 を含むブックマーク はてなブックマーク -  GCJ12 Round1A  - kojingharangの日記  GCJ12 Round1A  - kojingharangの日記 のブックマークコメント

間に合わなかったのでpracticeで。

A.Password Problem

02:01 |  A.Password Problem - kojingharangの日記 を含むブックマーク はてなブックマーク -  A.Password Problem - kojingharangの日記  A.Password Problem - kojingharangの日記 のブックマークコメント

  • B文字のパスワードをA文字まで打った。i番目の文字が正しく打てている確率はp[i]。以後正しい文字を打てるとして、0〜A文字削除して残りを打つ、あきらめてenterを押して再度全部打つという選択肢がある。残り打鍵数の期待値が一番低いものを計算する問題。
  • げげ、ぱっと見て確率DPみたいな感じ?と思ったけど、i番目の文字まで戻ったときに全部合ってる確率だけ分かればよいことが分かった。
int main() {
	int test_cases;
	cin>>test_cases;
	REP(ttt, test_cases) {
		int A, B;
		cin>>A>>B;
		
		double ans = 100000000;
		double co = 1.0;
		
		REP(i, A+1) {
			// co is prod[0, i)
			int bs = A-i;
			double p = (bs*2+B-A+1)*co+(bs*2+B-A+1+B+1)*(1-co);
//			cout<<bs<<" "<<p<<endl;
			ans=min(ans, p);
			if(i<A) {
				double in;
				cin>>in;
				co *= in;
			}
		}
		ans=min(ans, B+2.0); // enter right away
		cout<<"Case #"<<ttt+1<<": "<<setprecision(10)<<ans<<endl;
	}
	return 0;
}

B. Kingdom Rush

02:01 |  B. Kingdom Rush - kojingharangの日記 を含むブックマーク はてなブックマーク -  B. Kingdom Rush - kojingharangの日記  B. Kingdom Rush - kojingharangの日記 のブックマークコメント

  • レベルNまでの面があって各面を星1or2でクリアすることができる。各面に対して星1or2でクリアするに当たって必要な所持星数がきまってる。全面を星2でクリアするには最低何回クリアすればいいか。
  • 星2の必要星数が少ない順にクリアする。その際、所持星数が足りない場合は星1をクリアすることになる
  • 当初、星1の必要星数が少ない順でいいかと思ってたけどsmall通らず。
  • しばらくやってわからないのでギブアップして解説をみると、条件を満たす星1の中で星2の必要星数が多い順にクリアするといいらしい
  • 例えば (0 1) (0 3) のとき、面1星1→面1星2ではダメで面2星1→面1星2→面2星2でクリアする必要がある
  • 想定アルゴリズムが間違ってるっぽい時は、手動で反例を探すか全探索での答えと一致するかチェックしないといけないな...
int f(int N, vector<PII>& a, vector<PII>& b) {
	VI lvl(N);
//	sort(ALL(a));
	sort(ALL(b));
	int cur=0;
	int ok=1;
	int ans=0;
	REP(i, N) {
		REP(ai, N) {
			if(cur >= b[i].first) break;
			// find appropriate star1
			int idx=-1, maxb=-1;
			REP(j, N) {
				if(cur >= a[j].first && lvl[j]==0 && maxb < a[j].second) {
					idx=j;
					maxb = a[j].second;
				}
			}
			if(idx!=-1) {
				cur++;
				lvl[idx]=1;
//				cout<<"use 1 in "<<a[ai].first<<" "<<b[i].first<<endl;
				ans++;
			} else break;
		}
		if(cur < b[i].first) { ok=0; break; }
		cur+=lvl[b[i].second]==1 ? 1 : 2;
		lvl[b[i].second]=2;
	}
	return ok?N+ans:-1;
}

int main() {
	int test_cases;
	cin>>test_cases;
	REP(ttt, test_cases) {
		int N;
		cin>>N;
		vector<PII> a(N), b(N);
		REP(i, N) {
			cin>>a[i].first>>b[i].first;
			a[i].second = b[i].first;
			b[i].second=i;
		}
		int F = f(N, a, b);
//		int Ref = ref(N, a, b);
//		if(F!=Ref) {
//			cout<<"DIFF Case #"<<ttt+1<<" "<<F<<" "<<Ref<<endl;
//		}
		if(F!=-1) cout<<"Case #"<<ttt+1<<": "<<F<<endl;
		else cout<<"Case #"<<ttt+1<<": Too Bad"<<endl;
	}
	return 0;
}

2012-04-26

SRM 541 Div1 250 AntsMeet

10:38 |  SRM 541 Div1 250 AntsMeet - kojingharangの日記 を含むブックマーク はてなブックマーク -  SRM 541 Div1 250 AntsMeet - kojingharangの日記  SRM 541 Div1 250 AntsMeet - kojingharangの日記 のブックマークコメント

  • アリが東南西北の一定方向に同じ一定速度で動く。同じ場所で出会ったら消滅する。最後に残るのは何匹か。
  • すり抜けないように座標を2倍してシミュレーションする。
  • (4000*50*50=10,000,000ということでもしかすると微妙?と思ったけどOKだった)
class AntsMeet {
	public:
	int countAnts(vector <int> x, vector <int> y, string dir) {
		int N=x.size();
		VI live(N, 1);
		REP(i, N) {
			x[i]*=2;
			y[i]*=2;
		}
		REP(t, 4000) {
			VI nlive(live);
			REP(i, N) {
				if(!live[i]) continue;
				if(dir[i]=='N') y[i]++;
				if(dir[i]=='S') y[i]--;
				if(dir[i]=='E') x[i]++;
				if(dir[i]=='W') x[i]--;
			}
			REP(i, N) REP(j, N) if(i!=j && x[i]==x[j] && y[i]==y[j] && live[i] && live[j]) nlive[i]=nlive[j]=0;
			live=nlive;
		}
		return accumulate(ALL(live), 0);
	}
};

2012-04-15

GCJ2012 Qualification B. Dancing With the Googlers

10:55 |  GCJ2012 Qualification B. Dancing With the Googlers - kojingharangの日記 を含むブックマーク はてなブックマーク -  GCJ2012 Qualification B. Dancing With the Googlers - kojingharangの日記  GCJ2012 Qualification B. Dancing With the Googlers - kojingharangの日記 のブックマークコメント

  • 数字3つの tuple の合計値が N 個与えられる。N 個の元の tuple のうち、tuple の最大値 max, 最小値 min として max - min == 2 なのが S 個(surprisingと呼ぶ)、残りは max-min < 2 のとき、
  • 最大値が p 以上のものの数の最大値を求める問題。
  • 合計値が x のとき、surprising なら最大値は (x+2)/3, そうじゃなければ (x+4)/3 と一意に決まる
  • ので、合計値を降順にソートして greedy に処理する。
  • 全部 not surprising としておいて、p 以上のはそのままカウント
  • 超えてないもので surprising とすれば p 以上になるものは surprising 券がまだ使えるならカウント
int main() {
	int test_cases;
	cin>>test_cases;
	REP(ttt, test_cases) {
		int N, S, P;
		cin>>N>>S>>P;
		VI T(N);
		REP(i, N) cin>>T[i];
		sort(ALLR(T));
		//cout<<T<<endl;
		int ans = 0;
		REP(i, N) {
			if((T[i]+2)/3 >= P) ans++;
			else if(S>0 && T[i]>=2 && (T[i]+4)/3 >= P) {
				ans++;
				S--;
			}
		}
		cout<<"Case #"<<ttt+1<<": "<<ans<<endl;
	}
	return 0;
}

GCJ2012 Qualification C. Recycled Numbers

10:55 |  GCJ2012 Qualification C. Recycled Numbers - kojingharangの日記 を含むブックマーク はてなブックマーク -  GCJ2012 Qualification C. Recycled Numbers - kojingharangの日記  GCJ2012 Qualification C. Recycled Numbers - kojingharangの日記 のブックマークコメント

  • A <= n <= B <= 2000000 な n の各桁を回転させた数字 m が A <= n < m <= B になるような (n, m) の個数を重複なく求める問題。
  • 2000000 だから微妙かと思いつつ特に工夫なく書いたら大丈夫そうなので出した
  • 重複をカウントしない処理が抜けていて large 落ちた(´・ω・`)
  • small のテストケースに頼ってはいけない...
  • と思ったら small どころか sample 1111 2222 -> 287 とあって親切にも "Are we sure about the output to Case #4? Yes, we're sure about the output to Case #4." と書いてあったのであった。
  • diff が 288 と 287 を等しいと判定してしまった ... 目diff failed.

↓あとで

int main() {
	int test_cases;
	cin>>test_cases;
	REP(ttt, test_cases) {
		int A, B;
		cin>>A>>B;
		int sp=1;
		VI tb;
		VI tb2;
		while(B>sp*10) {
			sp*=10;
			tb.PB(sp);
		}
		REP(i, tb.size()) tb2.PB(sp*10/tb[i]);
		int ans=0;
		for(int i=A;i<=B;i++) {
			//cout<<"i "<<i<<endl;
			set<int> used;
			REP(j, tb.size()) {
				int b = i/tb[j] + (i%tb[j])*tb2[j];
				if(i<b && A<=b && b<=B && /* ADDED */ used.insert(b).second) {
					ans++;
					//cout<<b<<endl;
				}
			}
		}
		cout<<"Case #"<<ttt+1<<": "<<ans<<endl;
	}
	return 0;
}

GCJ2012 Qualification D. Hall of Mirrors

10:55 |  GCJ2012 Qualification D. Hall of Mirrors - kojingharangの日記 を含むブックマーク はてなブックマーク -  GCJ2012 Qualification D. Hall of Mirrors - kojingharangの日記  GCJ2012 Qualification D. Hall of Mirrors - kojingharangの日記 のブックマークコメント

  • 2次元の世界に鏡があって自分が立ってるので自分がいくつ見えるかを求める問題。
  • 難しそうなので部屋の壁にしか鏡がない small を考える
  • 反射するイコール対称な位置に自分がいるということなので鏡の向こうの自分をたくさん配置する
  • 各自分について、実際の自分の位置から見えるかどうか判定する。
  • 距離が近いほうから見ていって、同一直線上にあったらカウントしない
  • サンプルの 3x4 の部屋で 68 人も見える事にびっくり。実際のところは頭の幅とかあるからそんなに見えないかもしれないけど見てみたら怖そう...
  • small 通ったけど large わからん。解説をみる
int main() {
	int test_cases;
	cin>>test_cases;
	REP(ttt, test_cases) {
		int H,W,D;
		cin>>H>>W>>D;
		//cout<<H<<" "<<W<<" "<<D<<endl;
		
		int ox=0, oy=0;
		REP(h, H) {
			string s;
			cin>>s;
			REP(i, s.size()) if(s[i]=='X') {ox=i; oy=h;}
		}
		ox--;oy--;
		//cout<<ox<<" "<<oy<<endl;
		
		int ww = 100/(W-2)+1;
		int hh = 100/(H-2)+1;
		int ans = 0;
		vector<pair<int, PII> > l;
		for(int x=-ww;x<=ww;x++) {
			for(int y=-hh;y<=hh;y++) {
				int MX = x*(W-2)+(x%2==0 ? ox : W-2-ox-1)-ox;
				int MY = y*(H-2)+(y%2==0 ? oy : H-2-oy-1)-oy;
				int d = MX*MX+MY*MY;
				//if(d!=0 && d<=D*D) cout<<d<<"  "<<x<<" "<<y<<"    "<<MX<<" "<<MY<<endl;
				if(d!=0 && d<=D*D) l.PB(MP(d, MP(MX, MY)));
			}
		}
		//map<int, int> dh;
		
		sort(ALL(l));
		vector<PII> used;
		REP(i, l.size()) {
			int d = l[i].first;
			int MX=l[i].second.first;
			int MY=l[i].second.second;
			int ok=1;
			//cout<<"try "<<d<<" "<<MX<<" "<<MY<<endl;
			REP(j, used.size()) {
				int ux = used[j].first;
				int uy = used[j].second;
				if(MX*ux<0) continue;
				if(MY*uy<0) continue;
				if(ux==0) {
					if(MX!=0) continue;
					else {ok=0;break;}
				}
				if(uy==0) {
					if(MY!=0) continue;
					else {ok=0;break;}
				}
				int ug = GCD(ux, uy);
				int mg = GCD(MX, MY);
				if(ux/ug==MX/mg && uy/ug==MY/mg) {ok=0;break;}
			}
			if(ok) {
				//cout<<"X "<<d<<" "<<MX<<" "<<MY<<endl;
				//cout<<MX<<"\t"<<MY<<(MX==0 ? MY*10000000 : (double)MY/MX+(MX>0?1000:-1000))<<endl;
				//cout<<MX<<"\t"<<MY<<endl;
				ans++;
				used.PB(l[i].second);
				//dh[d]++;
			}
		}
		
		//vector<double> aa;
		//FOR(e, used) aa.PB(e->first==0 ? (double)e->second*1000000 : (double)e->second/e->first+(e->first>0?1000:-1000));
		//sort(ALL(aa));
		//REP(i, aa.size()-1) if(abs(aa[i]-aa[i+1]) < 0.00001) cout<<"ERROR"<<aa[i]<<" "<<aa[i+1]<<endl;
		//cout<<dh<<endl;
		cout<<"Case #"<<ttt+1<<": "<<ans<<endl;
	}
	return 0;
}

TCO12 Round1C 500 PasswordXGrid

09:06 |  TCO12 Round1C 500 PasswordXGrid - kojingharangの日記 を含むブックマーク はてなブックマーク -  TCO12 Round1C 500 PasswordXGrid - kojingharangの日記  TCO12 Round1C 500 PasswordXGrid - kojingharangの日記 のブックマークコメント

  • W x H グリッドの各辺にコストが与えられて、左上頂点から右下頂点に向かって後戻りしないで長さ W+H のパスで行くとき、どんなパスを通っても通ったとこのコストの和が同じになるように各辺のコストを大きくしたい。そうしたときのコストの和の最小値を求める問題。
  • 一番コストが高いパスのコストの和が答えなので左上からDP
  • 残り20分くらいしかなくて 250 がややこしかったので厳しいかなと思ったけど簡単でよかった
class PasswordXGrid {
	public:
	int minSum(vector <string> H, vector <string> V) {
		int N=H.size()-1;
		int M=H[0].size();
		VVI m(N+1, VI(M+1));
		cout<<M<<" "<<N<<endl;
		REP(y, N+1) {
			REP(x, M+1) {
				if(x-1>=0) m[y][x] = max(m[y][x], m[y][x-1]+H[y][x-1]-'0');
				if(y-1>=0) m[y][x] = max(m[y][x], m[y-1][x]+V[y-1][x]-'0');
			}
		}
		//cout<<m<<endl;
		return m[N][M];
	}
};

TCO12 Round1C 250 PasswordXGuessing

09:06 |  TCO12 Round1C 250 PasswordXGuessing - kojingharangの日記 を含むブックマーク はてなブックマーク -  TCO12 Round1C 250 PasswordXGuessing - kojingharangの日記  TCO12 Round1C 250 PasswordXGuessing - kojingharangの日記 のブックマークコメント

  • パスワードが決まってる(けど与えられない)。文字列がいくつか与えられて、各1文字を除いてそのパスワードと一致している。可能なパスワードが何通りあるか。
  • なにこれ難しいと焦る
  • 各桁の数字の候補を桁x10の配列で管理
  • 最初の文字列について、間違ってる文字の位置を仮定する
  • 間違ってるとこはその文字以外残るし、あってるとこはその文字だけ残る
  • 残りの文字列について、候補に含まれていることを確認する。だめなら仮定した桁はだめなので次。
  • その際、最初に仮定したとこ以外は正しいか間違ってるかわかるので優先して処理
  • その結果その文字列に関して間違ってる桁数によって決まってないとこが間違ってるかどうか決まるので間違ってたら候補を消す
  • 各桁の候補数を掛けて各仮定について和をとってのが答え
  • あとで他人のを見て、候補とか考えないで間違ってる桁を 9 通り試せばいいだけと分かった。
  • パスワードを仮定すれば残りの文字列で間違ってる桁がちゃんと1コかどうかを確かめて OK なら ans++ するだけでしたちゃんちゃん
  • long long はひっかけ
class PasswordXGuessing {
	public:
	long long howMany(vector <string> G) {
		int N=G.size();
		int X=G[0].size();
		ll ans=0;
		//cout<<endl;
		REP(wr, X) {
			VI can(X*10, 1);
			REP(j, X) {
				if(j==wr) {
					can[j*10+G[0][j]-'0']=0;
				} else {
					REP(z, 10) if(z!=G[0][j]-'0') can[j*10+z]=0;
				}
			}
			//cout<<can<<endl;
			int ok=1;
			for(int i=1;i<N;i++) {
				//cout<<i<<endl;
				int x=0;
				VI w(X);
				REP(j, X) {
					if(can[j*10+G[i][j]-'0']) {
						if(j!=wr) w[j]=1;
					} else {
						x++;
						w[j]=1;
					}
				}
				//cout<<i<<endl;
				if(x>1) {ok=0;break;}
				if(x==1) {
					REP(j, X) if(w[j]==0) REP(zz, 10) if(zz!=G[i][j]-'0') can[j*10+zz]=0;
				}
				if(x==0) {
					REP(j, X) if(w[j]==0) can[j*10+G[i][j]-'0']=0;
				}
				if(!ok) break;
			}
			if(!ok) continue;
			ll lans=1;
			REP(j, X) {
				ll a=0;
				REP(z, 10) a+=can[j*10+z];
				lans *= a;
			}
			//cout<<can<<endl;
			//cout<<"+ "<<lans<<endl;
			ans += lans;
		}
		return ans;
	}
};
|