Hatena::Grouptopcoder

SRM diary(Sigmar)

SigmarのTopcoder SRM参加記録など雑記です。
社会人になってから競技プログラミングを始めました。どこまで行けるか分かりませんが合間を見つけてアルゴリズムの勉強をしています。

2011-10-08Google Code Jam Japan 2011 決勝

  • A-small/A-Large:Passed, score:15, penalty(time):1:30:31, rank:281
  • 順位を気にせず、ずっとBをやっていたらとんでもない順位になってしまった

Google Code Jam Japan 2011 決勝 B バクテリアの増殖

| 20:56 | Google Code Jam Japan 2011 決勝 B バクテリアの増殖 - SRM diary(Sigmar) を含むブックマーク はてなブックマーク - Google Code Jam Japan 2011 決勝 B バクテリアの増殖 - SRM diary(Sigmar) Google Code Jam Japan 2011 決勝 B バクテリアの増殖 - SRM diary(Sigmar) のブックマークコメント

Problem Statement

解答方針

A^A mod Cって普通にbinary methodで計算するだけでは?

全然違った。指数のほうはmod Cではダメらしい。

Aの2乗、3乗、4乗、、、と順番にmod Cで計算してみて、同じものが出てくるまでやってみる

Cが素数のときはC-1回で循環するはずである。Cが素数でないときでも鳩の巣原理でC-1回を超えることはない。

X回で循環したとすると、指数をX減らしても同じ結果になるということだから、指数はmod Xで計算すれば良いのか?

サンプルの最後が合わない。

指数の計算がA^A mod Xとかでやってたけどこれがだめっぽい気がする。指数の計算用の指数も考える必要が・・・?

・・・

1時間半も経った。無邪気にやりすぎた。

Aに浮気。

解いて戻ってきた。


smallなら解けるだろうか?A乗1回するだけなら本当にbinary methodするだけでは?

1WA。違った。A乗を最大2回だった。結局smallの何がLargeより簡単なんだろう。よく分からない。


再びLargeを考える。

指数の計算方法も同じである気がする。Aの2乗、3乗、、、と順番にmod Xで計算すると、どこかで循環する

循環の長さは当然Xより小さいはずだから、これを繰り返していけばいつかXが1になるはずだ

mod 1なら常にAは0になるので、ここで収束する

実装してみる

サンプル合った

WA。原因は想像がついている。

A mod Xを何乗かしたとき、必ずしもAに戻ってくるわけではない。例えばA^5=A^2だがA^4!=A^1みたいなのがあると、指数が2~5の間で循環するわけだから、必ずしも常にmodを取っていいわけではない。

うーーーーーん

時間切れ


以下終了後

実は2~5で循環する場合でも、2以上のXの場合は((X-2)%3+2)乗すれば良いわけだから、結局mod 3で見ればX%3と合同であることは変わらない

ってことは、最大でも1000乗すれば循環が始まっていると見て間違いないのだから、単に1000以上になる場合だけ、modで合同の1000以上の最小値を保持しておけば良いはずだ

書いてみた

small/largeともにPass

コンテスト終了後1時間以上も経っていた

もっと頭の回転早くないと無理だな


ソースコード

ll powgf(ll a, ll e, ll MOD) {
	if(a==0) return a;
	ll res=1;
	ll bias=999/MOD*MOD+MOD;
	for(; e; e>>=1) {
		if(e&1) res*=a;
		if(res>=bias) res=(res-bias)%MOD+bias;
		a=a*a;
		if(a>=bias) a=(a-bias)%MOD+bias;
	}

	return res;
}

int solve(int A, int B, int C) {
	int res=0;

	int cyc[1010];
	int i=C;
	while(i) {
		int x=A%i;
		int memo[1010];
		memset(memo, -1, sizeof(memo));
		memo[x]=0;
		while(memo[x*A%i]<0) {
			memo[x*A%i]=memo[x]+1;
			x=x*A%i;
		}
		cyc[i]=memo[x]+1-memo[x*A%i];
		if(i==cyc[i]) break;
		i=cyc[i];
	}

	int a[1010];
	for(int i=1; i<=C; i++) a[i]=A;
	for(int i=0; i<B; i++) {
		int j=C;
		while(j) {
			a[j]=powgf(a[j], a[cyc[j]]?a[cyc[j]]:cyc[j], j);
			if(j==cyc[j]) break;
			j=cyc[j];
		}
	}
	res=a[C]%C;
	return res;
}

int main() {
	ifstream ifs("input.txt");
	ofstream ofs("output.txt");

	int testcase;
	ifs >> testcase; ifs.ignore();
	for(int testnum=1; testnum<=testcase; testnum++) {
		int A, B, C;
		ifs >> A >> B >> C;
		int res=solve(A, B, C);
		ofs << "Case #" << testnum << ": ";
		ofs << res << endl;
	}
}

Google Code Jam Japan 2011 決勝 A アンテナ修復

| 20:56 | Google Code Jam Japan 2011 決勝 A アンテナ修復 - SRM diary(Sigmar) を含むブックマーク はてなブックマーク - Google Code Jam Japan 2011 決勝 A アンテナ修復 - SRM diary(Sigmar) Google Code Jam Japan 2011 決勝 A アンテナ修復 - SRM diary(Sigmar) のブックマークコメント

Problem Statement

解答方針

Bから浮気してきた

よく分からんけど大きいやつ同士をくっつけたほうが面積大きくなるだろ

Greedyに大きいのをくっつけるコードを書いた。

small通った。

largeも通った。

何かBと比べてえらい簡単だな・・・


ソースコード

double solve(int K, vector <int> &E) {
	double res=0;
	
	sort(E.begin(), E.end(), greater <int>());
	res=(double)E[0]*E[1];
	double e0=E[0], e1=E[1];
	for(int i=2; i<K; i++) {
		res+=e0*E[i];
		e0=e1; e1=E[i];
	}
	res+=e0*e1;
	res*=sin(2*M_PI/K)/2;
	return res;
}

int main() {
	ifstream ifs("input.txt");
	ofstream ofs("output.txt");

	int testcase;
	ifs >> testcase; ifs.ignore();
	for(int testnum=1; testnum<=testcase; testnum++) {
		int K;
		ifs >> K;
		vector <int> E(K);
		for(int i=0; i<K; i++) ifs >> E[i];
		double res=solve(K, E);
		ofs << "Case #" << fixed << setprecision(15) << testnum << ": ";
		ofs << res << endl;
	}
}

Google Code Jam Japan 2011 決勝 C ワイルドカード

| 20:56 | Google Code Jam Japan 2011 決勝 C ワイルドカード - SRM diary(Sigmar) を含むブックマーク はてなブックマーク - Google Code Jam Japan 2011 決勝 C ワイルドカード - SRM diary(Sigmar) Google Code Jam Japan 2011 決勝 C ワイルドカード - SRM diary(Sigmar) のブックマークコメント

Problem Statement

解答方針

終了後にsmallだけ解いた。

というか基本的に全探索するだけ。こっちのほうがB-smallより簡単な気がする。


ソースコード

string solve(string a, string b) {
	int n=a.size();
	
	string best=a;
	int bestast=0;
	for(int mask=1; mask<(1<<n)-1; mask++) {
		string aa;
		int aaast=0;
		for(int i=0; i<n; i++) {
			if(mask&(1<<i)) {
				if(i==0 || aa[aa.size()-1]!=' ') {
					aaast++;
					aa.push_back(' ');
				}
			} else aa.push_back(a[i]);
		}
		vector <string> vs;
		istringstream iss(aa);
		copy(istream_iterator <string>(iss), istream_iterator <string>(), back_inserter(vs));
		for(int i=0; i<(int)aa.size(); i++) if(aa[i]==' ') aa[i]='*';

		bool ok=false;
		if(aa[0]!='*') {
			if(vs[0].size()>b.size() || vs[0]!=b.substr(0, vs[0].size())) ok=true;
		}
		if(aa[aa.size()-1]!='*') {
			if(vs[vs.size()-1].size()>b.size() || vs[vs.size()-1]!=b.substr(b.size()-vs[vs.size()-1].size(), vs[vs.size()-1].size())) ok=true;
		}

		int idx=0;
		for(int i=0; i<(int)b.size() && idx<(int)vs.size(); i++) {
			if(vs[idx].size()>b.size()-i) break;
			if(vs[idx]==b.substr(i, vs[idx].size())) {
				i=i+vs[idx].size()-1;
				idx++;
			}
		}
		if(idx<vs.size() || ok) {
			if(best.size()>aa.size() || best.size()==aa.size() && bestast>aaast || best.size()==aa.size() && bestast==aaast && best>aa) {
				best=aa;
				bestast=aaast;
			}
		}
	}

	return best;
}

int main() {
	ifstream ifs("input.txt");
	ofstream ofs("output.txt");

	int testcase;
	ifs >> testcase; ifs.ignore();
	for(int testnum=1; testnum<=testcase; testnum++) {
		string a, b;
		ifs >> a >> b;
		string res=solve(a, b);
		ofs << "Case #" << testnum << ": ";
		ofs << res << endl;
	}
}

NiiqiitoNiiqiito2013/02/17 11:57I hate my life but at least this makes it braeable.

xkhqsmsgifxkhqsmsgif2013/02/19 15:16E9CxwG <a href="http://cdmchajbiebt.com/">cdmchajbiebt</a>

トラックバック - http://topcoder.g.hatena.ne.jp/jackpersel/20111008