Hatena::Grouptopcoder

kojingharangの日記 RSSフィード

 | 

2011-12-29

SRM 練習

14:49 |  SRM 練習 - kojingharangの日記 を含むブックマーク はてなブックマーク -  SRM 練習 - kojingharangの日記  SRM 練習 - kojingharangの日記 のブックマークコメント

いくつか練習。

SRM 433 Div1 easy MagicWords

14:49 |  SRM 433 Div1 easy MagicWords - kojingharangの日記 を含むブックマーク はてなブックマーク -  SRM 433 Div1 easy MagicWords - kojingharangの日記  SRM 433 Div1 easy MagicWords - kojingharangの日記 のブックマークコメント

文字列を回転させたもののうち、元の文字列と一致するものが K 個になるようなのを magic word ということにして、

いくつかの文字列をいろんな順序でつなげたもののうち magic word になるようなやつの個数を求める。

  • 文字列の個数は最大8個なので、8! = 40320 ということでこれはそのまま全部試せばよさそう。
  • くっつけた文字列の長さ L の最大値は 8*20=160。magic word 判定は普通にやると長さ^2なので、160 * 160 * 40 320 = 1,032,192,000となってちょっと微妙そうな感じがする
  • 回転して元と一致する個数が k 個なら、その文字列は長さL/kの文字列が k 個つながってる という性質を利用
  • 先頭の L/k 文字と L/k*j からの L/k 文字がすべて一致する → 一致するものは k 個以上
  • このチェックだと一致する個数が 2 つの場合は 4 つの場合に含まれるので、一致する個数を大きい方から L~1 として見ていく。
  • k 個一致したらそこで終わりなので K と同じなら答えを1コ増やす。
  • N^2 っぽいけど、L mod k != 0 のときはチェックを端折れるので N^1.5 ほどになると思う。
class MagicWords {
	public:
	int count(vector <string> S, int K) {
		int N=S.size();
		VI p(N);
		REP(i, N) p[i]=i;
		int L = 0;
		REP(i, N) L+=S[i].size();
		if(L%K==0) {
			int ans = 0;
			do {
				string s = "";
				REP(i, N) s+=S[p[i]];
				for(int l=1;l<=L;l++) {
					if(L%l!=0) continue;
					int k=L/l;
					int ok=1;
					REP(i, L/k) REP(j, k) if(s[i]!=s[j*L/k+i]) ok=0;
					if(ok) {
						if(k==K) ans++;
						break;
					}
				}
				//cout<<s<<"  "<<ok<<endl;
			} while(next_permutation(ALL(p)));
			return ans;
		}
		return 0;
	}

SRM 363 Div1 easy HandsShaking

14:49 |  SRM 363 Div1 easy HandsShaking - kojingharangの日記 を含むブックマーク はてなブックマーク -  SRM 363 Div1 easy HandsShaking - kojingharangの日記  SRM 363 Div1 easy HandsShaking - kojingharangの日記 のブックマークコメント

社畜ビジネスマンが N 人円卓に座って、腕が交差しないように全員が握手する方法は何通りあるか。

  • f(n-k) から f(n) が作れないかいろいろ試行錯誤
  • ....
  • ....
  • 一組握手してしまえば、その左右は独立した領域になるので、f(n)=Σf(左の人数)*f(右の人数) で良さそう
  • それをメモ化。


ll memo[60];
ll f(int n) {
	ll ans = 0;
	if(n==0) return 1;
	if(memo[n]) return memo[n];
	for(int i=0;i<=n-2;i+=2) {
		int j=n-2-i;
		ans+=f(i)*f(j);
	}
	return memo[n]=ans;
}

class HandsShaking {
	public:
	long long countPerfect(int n) {
		memset(memo, 0, sizeof(memo));
		return f(n);
	}

成功体験++

SRM 528 Div2

14:07 | SRM 528 Div2 - kojingharangの日記 を含むブックマーク はてなブックマーク - SRM 528 Div2 - kojingharangの日記 SRM 528 Div2 - kojingharangの日記 のブックマークコメント

緑の人として参加。

225.99 WA WA 1191 -> 1152

ひきつづき緑の人。

250 MinCostPalindrome

14:07 |  250 MinCostPalindrome - kojingharangの日記 を含むブックマーク はてなブックマーク -  250 MinCostPalindrome - kojingharangの日記  250 MinCostPalindrome - kojingharangの日記 のブックマークコメント

  • 回文になるように ? を x か o に置き換えるときの最小コストを求める
  • 奇数の長さに対応してないコードに対してチャレンジしようとしたら、問題条件に書いてある通り長さは偶数だぜと言われる orz
class MinCostPalindrome {
	public:
	int getMinimum(string s, int oCost, int xCost) {
		int ans = 0;
		REP(i, s.size()/2) {
			if(s[i]=='?'&&s[s.size()-i-1]=='?') ans += min(oCost, xCost)*2;
			else if(s[i]=='?') ans += s[s.size()-i-1]=='o'?oCost:xCost;
			else if(s[s.size()-i-1]=='?') ans += s[i]=='o'?oCost:xCost;
			else if(s[i]!=s[s.size()-i-1]) return -1;
		}
		if(s.size()&1) if(s[s.size()/2]=='?') ans += min(oCost, xCost);
		return ans;
	}

500 Cut

14:07 |  500 Cut - kojingharangの日記 を含むブックマーク はてなブックマーク -  500 Cut - kojingharangの日記  500 Cut - kojingharangの日記 のブックマークコメント

  • eel ってうなぎらしい。
  • {14 20} 1 みたいなケースを考えてなくて failed system test.
  • あからさまにソートしてなかったのにチャレンジされなかった部屋ということで。

↓あとで通したもの

class Cut {
	public:
	int getMaximum(vector <int> es, int mc) {
		int ans = 0;
		sort(ALL(es));
		REP(jj, 2)
		FOR(v, es) {
			if(!(jj==0&&*v%10==0 || jj==1&&*v%10>0)) continue;
			while(*v>10 && mc>0) {
				*v-=10;
				ans++;
				if(*v>0) mc--;
			}
			if(*v==10) ans++;
		}
		return ans;
	}

1000 Mosquitoes

14:07 |  1000 Mosquitoes - kojingharangの日記 を含むブックマーク はてなブックマーク -  1000 Mosquitoes - kojingharangの日記  1000 Mosquitoes - kojingharangの日記 のブックマークコメント

数直線上で蚊がそれぞれの位置から等速直線運動をする。時刻と円の中心を適切に決めて半径R以内に入る蚊の最大数を求める。

  • 蚊の数も初期位置の範囲も小さいし、t>=200くらいでみんな外向きに広がってっちゃうので 0~300 を微小時間に分けて円の端の位置を全通り試してみよう
  • 最大の速さ 100 なので 0.01 秒単位でいいかな
  • サンプルと、速さ100のときのテストも通ったので出したら failed system test.
  • よーく追って見ると、0.777777777... のときに一瞬だけ 4 匹が半径 1 以内に入るケースで 3 匹と答えていた。。
  • 物理シミュレーションで薄い壁をボールが通り抜けちゃったみたいな感じ。
  • 任意の2匹の蚊の距離が 2R になる瞬間すべてについて位置を求めてソートしてどこまで R に入ってるか確かめると良いらしい。
  • 変化は連続なんだけど求める答えが変わらないような有限のサンプルに落とすという例であろう。

↓最初に書いただめなやつ

class Mosquitoes { 
  public: 
  int getMaximum(vector <int> xInit, vector <int> v, int R) { 
    int ans = -1; 
    //int K=2; 
    int KT=100; 
    REP(idx, v.size()) 
    for(int side=-1;side<=1;side+=2) 
    { 
      for(int t=0;t<300*KT;t++) 
      { 
        double x = (xInit[idx]+(double)t/KT*v[idx])+side*R; 
        int lans = 0; 
        REP(i, v.size()) lans += fabs(x - (xInit[i]+(double)t/KT*v[i]))<=R; 
        ans = max(ans, lans); 
      } 
    } 
    return ans; 
  } 

↓後で通したやつ

class Mosquitoes {
	public:
	int getMaximum(vector <int> xInit, vector <int> v, int R) {
		int ans = -1;
		vector<double> ts;
		int N = v.size();
		REP(i, N) REP(j, N) {
			if(i==j || v[i]==v[j]) continue;
			double t0 = (xInit[i]-xInit[j]-2.0*R)/(v[j]-v[i]);
			if(t0>=0.0) ts.push_back(t0);
			double t1 = (xInit[i]-xInit[j]+2.0*R)/(v[j]-v[i]);
			if(t1>=0.0) ts.push_back(t1);
		}
		ts.push_back(0.0);
		//cout<<ts<<endl;
		vector<double> pos(N);
		FOR(t, ts) {
			REP(i, N) pos[i] = xInit[i]+*t*v[i];
			sort(ALL(pos));
			REP(i, N) {
				for(int j=i;j<N;j++) {
					if(pos[j] - pos[i] <= 2.0*R+0.00000001) ans = max(ans, j-i+1);
				}
			}
		}
		return ans;
	}

 |