<?xml version="1.0" encoding="utf-8" ?>
<rss version="2.0"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xml:lang="ja">
	<channel>
		<title>naoya_t@topcoder</title>
		<link>http://topcoder.g.hatena.ne.jp/n4_t/</link>
		<description>naoya_t@topcoder</description>
		<dc:creator>n4_t</dc:creator>


		<item>
			<title>SRM534 − 今日は出ましたがrating減</title>
			<link>https://topcoder.g.hatena.ne.jp/n4_t/20120224/1330097323</link>

			<description><![CDATA[
		<div class="section">
			<p>（<a href="http://naoyat.hatenablog.jp/entry/2012/02/24/233000" target="_blank">http://naoyat.hatenablog.jp/entry/2012/02/24/233000</a> からの転載）</p>
			<ul>
				<li> Easy(250): ◯&lt;148.47&gt;</li>
				<li> Medium(500): 撃沈&lt;0&gt;</li>
				<li> Hard(1000): 開いた&lt;0&gt;</li>
			</ul>
			<p>12/20 in the room, 414/717 in Div1</p>
			<p>1652 -&gt; 1610</p>
			<p>なんか最近Easyは<a class="keyword" href="https://topcoder.g.hatena.ne.jp/keyword/DP">DP</a>有りで、Mediumはかなりうまく書かないと<a class="keyword" href="https://topcoder.g.hatena.ne.jp/keyword/TLE">TLE</a>/MLEになるぎりぎりの設定になってる印象。</p>
			<h4> Easy (250): EllysCheckers</h4>
			<ul>
				<li>こういうNim系が相変わらず苦手で困る</li>
				<li>checkerの数が0の局面から逆方向に考えていく<a class="keyword" href="https://topcoder.g.hatena.ne.jp/keyword/DP">DP</a></li>
				<li>boardのサイズが最大20なので状態数は2^20=1048576</li>
				<li>148.47 points (27'52'')</li>
				<li>Passed system test</li>
			</ul>
<pre>
#include &#60;iostream&#62;
#include &#60;sstream&#62;
#include &#60;cstdio&#62;
#include &#60;algorithm&#62;
#include &#60;string&#62;
#include &#60;vector&#62;
using namespace std;
#define sz(a)  int((a).size())
#define pb  push_back
#define rep(var,n)  for(int var=0;var&#60;(n);var++)
#define all(c)  (c).begin(),(c).end()

class EllysCheckers {
 public:
  string getWinner(string board) {
    int s=sz(board);
    int n=1&#60;&#60;s;
    vector&#60;int&#62; dp(n,-1);
    dp&#91;0] = 0;
    for (int x=0; x&#60;n; x++) {
      for (int m=1; m&#60;=x; m&#60;&#60;=1) {
        if (m&#38;x) {
          int m_ = m &#60;&#60; 1;
          if (m_ &#60; n &#38;&#38; !(m_ &#38; x)) {
            int y = (x - m) | m_;
            dp&#91;y] = 1-dp&#91;x];
          }
          int _mmm = m&#42;7, mmmm = m&#42;15;
          if (mmmm &#60; n &#38;&#38; (x &#38; mmmm) == _mmm) {
            int y = (x - _mmm) | (_mmm &#60;&#60; 1);
            dp&#91;y] = 1-dp&#91;x];
          }
        }
      }
      if ((x &#38; 1) == 0) {
        int y = x|1;
        dp&#91;y] = 1-dp&#91;x];
      }
    }
    int b=0; rep(i,s-1) b = b&#42;2 + ((board&#91;i]==&#39;o&#39;)?1:0);
    return dp&#91;b] ? &#34;YES&#34; : &#34;NO&#34;;
  }
};
</pre>

			<h4> Medium (500): EllysNumbers</h4>
			<ul>
				<li>数の集合が与えられ、互いに素であるような部分集合で積がnである組み合わせが何通りあるか</li>
				<li>nの約数以外は捨ててよさそう。1が入ってる場合は答えを2倍にすればよさそう。</li>
				<li>集合の要素を端から1つずつ掛けたり掛けなかったりして行く感じのメモ化再帰を書いてみた。新たに掛ける数とそこまでの積とのgcdが1でない場合は掛けられない縛り</li>
			</ul>
<pre>
#include &#60;sstream&#62;
#include &#60;algorithm&#62;
#include &#60;string&#62;
#include &#60;vector&#62;
#include &#60;map&#62;
#include &#60;set&#62;
using namespace std;
typedef long long ll;
#define sz(a)  int((a).size())
#define pb  push_back
#define rep(var,n)  for(int var=0;var&#60;(n);var++)
#define all(c)  (c).begin(),(c).end()
#define tr(c,i)  for(typeof((c).begin()) i=(c).begin(); i!=(c).end(); i++)
#define found(s,e)  ((s).find(e)!=(s).end())

ll gcd(ll m, ll n)
{
  if (m == 0 || n == 0) return 0LL;
  if (m == 1 || n == 1) return 1LL;
  if (m == n) return m;
  while (1) {
        if (m == 0) return n;
        if (n == 0) return m;
        if (m &#62; n) m %= n; else n %= m;
  }
}

class EllysNumbers {
  vector&#60;ll&#62; ns;
  int nn;
  ll n_;

  map&#60;pair&#60;ll,int&#62;,ll&#62; mm;

  ll sub(ll x, int ix) {
    if (ix == nn) return (x == n_ ? 1LL : 0LL);

    pair&#60;ll,int&#62; k(x, ix);
    if (found(mm,k)) return mm&#91;k];

    if (gcd(x, ns&#91;ix]) == 1) {
      return mm&#91;k] = sub(x&#42;ns&#91;ix], ix+1) + sub(x, ix+1);
    } else {
      return mm&#91;k] = sub(x, ix+1);
    }
  }

 public:
  long long getSubsets(long long n, vector &#60;string&#62; special) {
    n_ = n;
    stringstream ss;
    tr(special,it) ss &#60;&#60; &#42;it; ss &#60;&#60; &#34; &#34;;
    string s = ss.str(); int sn = s.size();
    ll a = 0;
    vector&#60;ll&#62; nums;
    rep(i,sn) {
      if (s&#91;i] == &#39; &#39;) {
        if (a &#62;= 0) nums.pb(a);
        a = -1;
      } else {
        ll b = (ll)(s&#91;i] - &#39;0&#39;);
        if (a &#62;= 0) a = a&#42;10LL + b;
        else a = b;
      }
    }

    set&#60;ll&#62; nset; bool has1 = false;
    tr(nums,it) {
      if (&#42;it == 1) { has1 = true; continue; }
      if (n % &#42;it) continue;
      nset.insert(&#42;it);
    }
    ns.assign(all(nset));
    nn = ns.size();
    if (nn == 0) return 0LL;
    if (nn == 1 &#38;&#38; ns&#91;0] != n) return 0LL;

    mm.clear();
    return sub(1LL, 0) &#42; (has1 ? 2 : 1);
  }
};
</pre>

			<ul>
				<li>しかし撃墜される。<a class="keyword" href="https://topcoder.g.hatena.ne.jp/keyword/TLE">TLE</a>？MLE？</li>
			</ul>
			<h5>再考</h5>
			<ul>
				<li>積の要素が互いに素であるという条件はもっと活用すべき。nも集合各要素も素因数分解してみて、例えばnが2^3を持つなら2^2,2^1を持つ要素は排除できるよね</li>
				<li>n≦1e18ならnは高々15種類の素数（の累乗）の積と考えてよさそう。cf. (2^1)*(3^1)*(5^1)*(7^1)*(11^1)*(13^1)*(17^1)*(19^1)*(23^1)*(29^1)*(31^1)*(37^1)*(41^1)*(43^1)*(47^1)=614889782588491410</li>
				<li>nとspecial integersをそれぞれ nに含まれる素因数の有無をビットのon/offで表したら最長15ビット(&lt;32768)</li>
				<li>special integersは高々500種類なので500*32768=16384000; long longだと131072000バイトでMLE。</li>
				<li>もしかして答えが32bit intを超えることがない？だとしたら32bit intで確保して65536000バイト。</li>
				<li>でもMLE…もしかしてこれって64MB制限に引っかかる？</li>
				<li>practice roomで実際にアロケートできたのがsizeof(int)*484*32768=63438848バイト。</li>
				<li>ああーもういいや最初の484個だけメモって残り16個ぐらい何度でも再帰させてしまえ</li>
				<li>これでpassed system test</li>
			</ul>
<pre>
#include &#60;iostream&#62;
#include &#60;sstream&#62;
#include &#60;cstring&#62;
#include &#60;algorithm&#62;
#include &#60;string&#62;
#include &#60;vector&#62;
#include &#60;map&#62;
#include &#60;set&#62;
using namespace std;
typedef long long ll;
#define sz(a)  int((a).size())
#define pb  push_back
#define rep(var,n)  for(int var=0;var&#60;(n);var++)
#define all(c)  (c).begin(),(c).end()
#define tr(c,i)  for(typeof((c).begin()) i=(c).begin(); i!=(c).end(); i++)
#define found(s,e)  ((s).find(e)!=(s).end())

ll gcd(ll m, ll n)
{
  if (m == 0 || n == 0) return 0LL;
  if (m == 1 || n == 1) return 1LL;
  if (m == n) return m;
  while (1) {
        if (m == 0) return n;
        if (n == 0) return m;
        if (m &#62; n) m %= n; else n %= m;
  }
}

class EllysNumbers {
  vector&#60;int&#62; ns; // 15bit
  int nn, allocated;
  int n_; // 15bit

  int &#42;mm;

  ll sub(int x, int ix) { // 15bit, 500=9bit
    if (ix == nn) return (x == n_ ? 1LL : 0LL);

    int k = (ix &#60;&#60; 15) | x;
    if (ix &#60; allocated &#38;&#38; mm&#91;k] &#62;= 0) return mm&#91;k];

    ll ans = sub(x, ix+1);
    if ((x &#38; ns&#91;ix]) == 0) ans += sub(x | ns&#91;ix], ix+1);

    if (ix &#60; allocated) mm&#91;k] = ans;
    return ans;
  }

  bool has1;

 public:
  bool prepare(long long n, vector&#60;string&#62; special) {
    // special integersをパース
    stringstream ss;
    tr(special,it) ss &#60;&#60; &#42;it; ss &#60;&#60; &#34; &#34;;
    string s = ss.str(); int sn = s.size();
    ll a = 0;
    vector&#60;ll&#62; nums;
    rep(i,sn) {
      if (s&#91;i] == &#39; &#39;) {
        if (a &#62;= 0) nums.pb(a);
        a = -1;
      } else {
        ll b = (ll)(s&#91;i] - &#39;0&#39;);
        if (a &#62;= 0) a = a&#42;10LL + b;
        else a = b;
      }
    }

    // エラトステネスのふるい
    char sieve&#91;32768+1];
    memset(sieve, 1, 32768+1);

    sieve&#91;0] = sieve&#91;1] = false;
    for (int i=3; i&#60;32768; i+=2) {
      sieve&#91;i+1] = false;
      if (!sieve&#91;i]) continue;
      for (int j=i&#42;2; j&#60;32768; j+=i) sieve&#91;j] = false;
    }

    int primes&#91;3512], j=0;
    rep(i,32768) if (sieve&#91;i]) primes&#91;j++] = i; // 3512 primes in &#91;0 .. 32767]

    // special integers の中で要らない子を捨てつつ、それぞれを素因数分解
    set&#60;ll&#62; nset; has1 = false;
    set&#60;int&#62; used_primes; map&#60;int,int&#62; max_fact;
    map&#60;ll,map&#60;int,int&#62; &#62; pset;
    tr(nums,it) {
      int num = &#42;it; if (num == 1) { has1 = true; continue; }
      if (n % num) continue;

      // prime factorization
      map&#60;int,int&#62; ps;
      int x = num;
      rep(j,3512){
        int prime = primes&#91;j];
        while (x % prime == 0) {
          if (found(ps,prime))
            ps&#91;prime]++;
          else
            ps&#91;prime] = 1;
          x /= prime;
        }
      }
      if (x &#62; 1) ps&#91;x] = 1;

      tr(ps,pt) {
        used_primes.insert(pt-&#62;first);
        if (found(max_fact, pt-&#62;first))
          max_fact&#91;pt-&#62;first] = max(max_fact&#91;pt-&#62;first], pt-&#62;second);
        else
          max_fact&#91;pt-&#62;first] = pt-&#62;second;
      }

      nset.insert(num);
      pset&#91;num] = ps;
    }
    nn = nset.size();
    if (nn == 0) return false;
    if (nn == 1 &#38;&#38; &#42;nset.begin() != n) return false;

    // special integersで使った素数のみでnを素因数分解。できなければ return 0
    ll x = n;
    map&#60;int,int&#62; n_fact;
    tr(max_fact,it) {
      ll prime = (int)it-&#62;first;
      int f = 0, maxf = it-&#62;second;
      while (x % prime == 0) {
        ++f; x /= prime;
      }
      if (f) n_fact&#91;prime] = f;
      if (f &#62; maxf) return false;
    }
    if (x != 1) return false;

    map&#60;int,int&#62; n_fact_map;
    n_ = 0;
    int ix = 0;
    tr(n_fact,it) {
      n_ |= (1 &#60;&#60; ix);
      n_fact_map&#91;it-&#62;first] = ix++;
    }

    // nで使われていない素因数を含むspecial integersを排除
    ns.clear();
    tr(pset,it) {
      int bs = 0;
      bool use_this = true;
      tr(it-&#62;second,jt) {
        int prime = jt-&#62;first, f = jt-&#62;second;
        if (!found(n_fact, prime) || f != n_fact&#91;prime]) { use_this = false; break; }
        bs |= (1 &#60;&#60; n_fact_map&#91;prime]);
      }
      if (use_this) ns.push_back(bs);
    }
    nn = ns.size();

    return true;
  }

  long long getSubsets(long long n, vector&#60;string&#62; special) {
    if (!prepare(n, special)) return 0LL;

    //mm.assign(500&#42;32768, -1);
    allocated = 0;
    for (int sz=500; sz&#62;0; --sz) {
      mm = (int &#42;)malloc(sizeof(int)&#42;sz&#42;32768);
      if (mm) { allocated = sz; break; }
    }

    ll ans = 0;
    if (mm) {
      memset(mm, -1, sizeof(int)&#42;allocated&#42;32768);
      ans = sub(0, 0) &#42; (has1 ? 2 : 1);
      free((void&#42;)mm);
    }
    return ans;
  }
};
</pre>

			<h4> Hard (1000): EllysString</h4>
			<ul>
				<li>Mediumを提出して５分ぐらい残ってたので開いてみた。Levenshtein距離的な何かを求める問題。文字の置き換えと、隣接する2文字の交換が許されている。</li>
				<li>あとで考える</li>
			</ul>

		</div>
]]></description>

			<dc:creator>n4_t</dc:creator>

			<pubDate>Fri, 24 Feb 2012 15:28:43 GMT</pubDate>



		</item>

		<item>
			<title> SRM533 - 深夜開催のSRMがちょっと辛い今日この頃</title>
			<link>https://topcoder.g.hatena.ne.jp/n4_t/20120220/1329670554</link>

			<description><![CDATA[
		<div class="section">
			<p>（<a href="http://naoyat.hatenablog.jp/entry/2012/02/20/014918" target="_blank">http://naoyat.hatenablog.jp/entry/2012/02/20/014918</a> からの転載）</p>
			<p>最近ちょっと早寝早起きサイクルになってるので2amからとかちょっときついですね。</p>
			<p>というわけでSRM533の問題を見てみた話。配点的には250-500-1000ですが・・・</p>
			<p>出てたら430位ぐらいでレーティング横ばい〜微減、かな。</p>
			<a name="seemore"></a>

		</div>
]]></description>

			<dc:creator>n4_t</dc:creator>

			<pubDate>Sun, 19 Feb 2012 16:55:54 GMT</pubDate>



		</item>

		<item>
			<title> SRM532 - 寝倒した先日の問題を見てみた</title>
			<link>https://topcoder.g.hatena.ne.jp/n4_t/20120216/1329670497</link>

			<description><![CDATA[
		<div class="section">
			<p>（<a href="http://naoyat.hatenablog.jp/entry/2012/02/16/184337" target="_blank">http://naoyat.hatenablog.jp/entry/2012/02/16/184337</a> からの転載）</p>
			<p>300 - 450 - 1000 ってまた気持ち悪い配点だけれど、本番じゃないしMediumから手をつけてみようかと。</p>
			<a name="seemore"></a>

		</div>
]]></description>

			<dc:creator>n4_t</dc:creator>

			<pubDate>Sun, 19 Feb 2012 16:54:57 GMT</pubDate>



		</item>

		<item>
			<title>[過去問]SRM531 Div1 Medium: MonsterFarm</title>
			<link>https://topcoder.g.hatena.ne.jp/n4_t/20120131/1328030993</link>

			<description><![CDATA[
		<div class="section">
			<p>なんかEasyより簡単そうに思えたんだけど、やってみて5回目でSystem Test通った程度の体たらくなのでまあEasy頑張っておいてよかった的な。</p>
			<a name="seemore"></a>

		</div>
]]></description>

			<dc:creator>n4_t</dc:creator>

			<pubDate>Tue, 31 Jan 2012 17:29:53 GMT</pubDate>


			<category>過去問</category>


		</item>

		<item>
			<title> SRM531 - 1年3ヶ月ぶりのTopCoder参戦</title>
			<link>https://topcoder.g.hatena.ne.jp/n4_t/20120131/1328022027</link>

			<description><![CDATA[
		<div class="section">
			<p>（<a href="http://naoyat.hatenablog.jp/entry/2012/01/31/235459" target="_blank">http://naoyat.hatenablog.jp/entry/2012/01/31/235459</a> からの転載）</p>
			<p>1/31 21:05〜</p>
			<p>久しぶりすぎて緊張する</p>
			<p>300-500-1000だ</p>
			<p>Easy300点は不吉</p>
			<a name="seemore"></a>

		</div>
]]></description>

			<dc:creator>n4_t</dc:creator>

			<pubDate>Tue, 31 Jan 2012 15:00:27 GMT</pubDate>



		</item>

	</channel>
</rss>
