Hatena::Grouptopcoder

cafelier@SRM

cafelier のSRM参加記録です。コンテスト中に考えてたことを執拗に全部書き残すとどうなるだろうかという試み本番中にこういうコードが書きたかったなあ、という後で書いた反省コードを書き残す試み

スパムが来たのでしばらくコメント欄をはてなユーザ限定にしています、すみません、

 | 

2009-06-14

SRM442

| 02:54 | はてなブックマーク -  SRM442 - cafelier@SRM

SRM442 の成績・ソース (要ログイン) : AC/WA/- : うひゃー

550開く

  • 点数的に難しそうだから950に行ってみた方がいいかなーと思いながらもいつも通りに真ん中から行く
  • 『1x5のタイルを横に並べて5x5とタテに並べて5x5で作ったブロックの市松模様が無限にあるときにx1,y1,x2,y2を切り取ってできる模様を作りたい。1x5タイルは何個必要か。1つの1x5を1x2と1x3に分けて使ったりして良い』

  • 気合いで延々と書くしか思いつかないなあ。
  • 気合いで延々と書いた。40分くらいかかった。
    • x1,y1 が一番左上エリアにくるようにmod 5的にずらしたりxとy反転したり
    • x1-x2とy1-y2の幅が広いときと狭いときの4通りで場合分け
    • しんどい
  • まあサンプル通ったので適当に…出しちゃえ。
    • こんなソースぜったいコーナーケース間違えてる気もするけど、かといってコーナーになるようなケースも特にないようなするし…まあなんでもいいや…

250開く

  • 『AからBまでの範囲で、素因数分解した時の項数が素数な値の個数は』
  • ≦100000。

  • 素数判定/素因数分解を O(log 100000) でできるから、それかける100000でも余裕
    • 素因数分解の項数数えて1だったら素数だから、ルーチンひとつで綺麗にかけるなあ
  • 書いた。サンプル通った。出しちゃえ。

950開く

  • 25分近く残ってる。しかもスコアボード見たら凄い数の人が解いてる!解きたい!問題文長い!
  • 『長いので略』

  • とりあえず、company ごとに完全に問題が独立だから、それぞれ別にconflictを最小化して足し算すればよい。
  • というループだけ書いた。

  • で、companyごとには?
  • 同盟関係グラフ書いてagencyがあるところを塗ったり既にguardいるところに印付けたり色々しながら考えてるタイム
  • どうみてもなんかグラフのマッチングかフローになりそうなんだけどなーと思って仮想頂点足したり引いたり
    • だめだなー全然そっちに落ちない
  • なんかグリーディーな戦略で行けたり?
    • guard増やして改善するところに置いていってなくなるまでやる。
    • 2秒で反例が作れた。ダメだ。
  • そのままタイムアップ

撃墜タイム

  • いちおう550を開いてみる…みんな自分のに負けず劣らず酷いコードだ読む気がしない…
  • 250を下から順に見てみる。
    • 素因数分解のループで毎回素数判定入れてる人がいる。これ大きい素数で軒並み1000000×log 100000回近いループになるはずで、そういう素数の分考えると時間ヤバいのでは
    • とりあえず保留

  • いろいろ見て回る
    • なんかトチ狂って i*i<=p みたいな終了条件がiが100000くらいになるとintオーバーフローするんじゃないか自分のソース、みたいなことが心配になりだした。
    • んで同じ事をやってる人に2,100000とか投げてみてチャレンジ失敗する。寝ぼけすぎです

  • うわー自分の550落とされてる!
  • これはもうダメだなーダメ元でさっきの遅そうな人にチャレンジしちゃえ
    • 失敗する。

感想

  • 950が解けないのは単なる実力不足だからいいとして、
  • 550みたいなのどうすればいいのかな。ううむ

SRM442 550

| 12:59 | はてなブックマーク -  SRM442 550 - cafelier@SRM

とりあえず通るには通ったけど、こんなもの*絶*対*に*ミスなく書けるわけがないし、解けたとはいえない…。どうしたものかな。x方向の分割とy方向の分割を分離して3分割を2段みたいな書き方をしたら少しはマシになるだろうか。

typedef long long LL;

class BedroomFloor { public:
  long long numberOfSticks(int x1, int y1, int x2, int y2) 
  {
    #define F(x) ((x)/5*5) // floor
    #define C(x)  F((x)+4) // ceil

    LL b[6] = {};
    if( F(x1)==F(x2) )
      if( F(y1)==F(y2) )
      {
        count_s(x1, x2, y1, y2, b);
      }
      else
      {
        count_s (x1, x2,   y1,  C(y1), b);
        count_my(x1, x2, C(y1), F(y2), b);
        count_s (x1, x2, F(y2),   y2 , b);
      }
    else
      if( F(y1)==F(y2) )
      {
        count_s(x1, C(x1), y1, y2, b);
        //
        count_mx(C(x1), F(x2), y1, y2, b);
        //
        count_s(F(x2), x2, y1, y2, b);
      }
      else
      {
        count_s (  x1 , C(x1),   y1,  C(y1), b);
        count_my(  x1 , C(x1), C(y1), F(y2), b);
        count_s (  x1 , C(x1), F(y2),   y2 , b);
        //
        count_mx(C(x1), F(x2),   y1,  C(y1), b);
        count_l (C(x1), F(x2), C(y1), F(y2), b);
        count_mx(C(x1), F(x2), F(y2),   y2 , b);
        //
        count_s (F(x2),   x2 ,   y1 , C(y1), b);
        count_my(F(x2),   x2 , C(y1), F(y2), b);
        count_s (F(x2),   x2 , F(y2),   y2 , b);
      }
    return optimize(b[1], b[2], b[3], b[4], b[5]);
  }

  bool is_horizontal(LL x, LL y)
  {
    return x/5%2 == y/5%2;
  }

  void count_s(LL x1, LL x2, LL y1, LL y2, LL b[])
  {
    if( is_horizontal(x1, y1) )
      b[x2-x1] += y2-y1;
    else
      b[y2-y1] += x2-x1;
  }

  void count_my(LL x1, LL x2, LL y1, LL y2, LL b[])
  {
    LL n=(y2-y1)/5, n1=n/2,  n2=(n+1)/2;
    b[x2-x1] +=       5 * (is_horizontal(x1,y1) ? n2 : n1);
    b[5]     += (x2-x1) * (is_horizontal(x1,y1) ? n1 : n2);
  }

  void count_mx(LL x1, LL x2, LL y1, LL y2, LL b[])
  {
    LL n=(x2-x1)/5, n1=n/2,  n2=(n+1)/2;
    b[y2-y1] +=       5 * (is_horizontal(x1,y1) ? n1 : n2);
    b[5]     += (y2-y1) * (is_horizontal(x1,y1) ? n2 : n1);
  }

  void count_l(LL x1, LL x2, LL y1, LL y2, LL b[])
  {
    b[5] += ((x2-x1)/5) * ((y2-y1)/5) * 5;
  }

  LL optimize( LL b1, LL b2, LL b3, LL b4, LL b5 )
  {
    LL total = 0;
    for(int k=6*6*6*6*6; --k>0; )
    {
      int k1 = k%6;
      int k2 = k/6%6;
      int k3 = k/6/6%6;
      int k4 = k/6/6/6%6;
      int k5 = k/6/6/6/6%6;
      if( 1*k1 + 2*k2 + 3*k3 + 4*k4 + 5*k5 <= 5 )
      {
        LL n = 1LL<<62;
        if(k1) n = min(n, b1/k1);
        if(k2) n = min(n, b2/k2);
        if(k3) n = min(n, b3/k3);
        if(k4) n = min(n, b4/k4);
        if(k5) n = min(n, b5/k5);
        total += n;
        b1 -= n*k1;
        b2 -= n*k2;
        b3 -= n*k3;
        b4 -= n*k4;
        b5 -= n*k5;
      }
    }
    assert( b1==0 && b2==0 && b3==0 && b4==0 && b5==0 );
    return total;
  }
};

再々挑戦。

(x1,y1)-(x2,y2)が同じ5x5に収まるまで分解し尽くすようにしてみた。こんなもんかなあ。

class BedroomFloor { public:
  LL b[6];

  long long numberOfSticks(int x1, int y1, int x2, int y2) 
  {
    b[1] = b[2] = b[3] = b[4] = b[5] = 0;

    devideX_and_count(x1, x2, y1, y2);
    return optimize();
  }

  // utils
  LL FLOOR(LL x) { return x/5*5; }
  LL CEIL (LL x) { return FLOOR(x+4); }

  // counting routines
  void devideX_and_count(LL x1, LL x2, LL y1, LL y2)
  {
    if( FLOOR(x1) == FLOOR(x2) )
      devideY_and_count(x1, x2, y1, y2, 1);
    else
      devideY_and_count(         x1,    CEIL(x1), y1, y2, 1 ),
      devideY_and_count(   CEIL(x1),  CEIL(x1)+5, y1, y2, ((FLOOR(x2)-CEIL(x1))/5+1)/2 ),
      devideY_and_count( CEIL(x1)+5, CEIL(x1)+10, y1, y2, ((FLOOR(x2)-CEIL(x1))/5+0)/2 ),
      devideY_and_count(  FLOOR(x2),          x2, y1, y2, 1 );
  }

  void devideY_and_count(LL x1, LL x2, LL y1, LL y2, LL rep)
  {
    if( FLOOR(y1) == FLOOR(y2) )
      count(x1, x2, y1, y2, rep);
    else
      count(x1, x2,         y1,    CEIL(y1), rep),
      count(x1, x2,   CEIL(y1),  CEIL(y1)+5, rep*(((FLOOR(y2)-CEIL(y1))/5+1)/2) ),
      count(x1, x2, CEIL(y1)+5, CEIL(y1)+10, rep*(((FLOOR(y2)-CEIL(y1))/5+0)/2) ),
      count(x1, x2,  FLOOR(y2),         y2 , rep);
  }

  void count(LL x1, LL x2, LL y1, LL y2, LL rep)
  {
    if( x1/5%2 == y1/5%2 ) // is_horizontal
      b[x2-x1] += rep*(y2-y1);
    else
      b[y2-y1] += rep*(x2-x1);
  }

  // compute minimum number of 1x5 blocks required (by greedily removing larger blocks)
  LL optimize()
  {
    LL total = 0;
    for(int K=6*6*6*6*6; --K>0; )
    {
      int k[] = {-1, K%6, K/6%6, K/6/6%6, K/6/6/6%6, K/6/6/6/6%6};
      if( 1*k[1] + 2*k[2] + 3*k[3] + 4*k[4] + 5*k[5] <= 5 )
      {
        LL n = 1LL<<62;
        for(int i=1; i<=5; ++i)
          if( k[i] )
            n = min(n, b[i]/k[i]);
        for(int i=1; i<=5; ++i)
          b[i] -= n*k[i];
        total += n;
      }
    }
    return total;
  }
};
トラックバック - https://topcoder-g-hatena-ne-jp.jag-icpc.org/cafelier/20090614
 | 

presented by cafelier/k.inaba under CC0