2011年10月23日日曜日

School Regional Team Contest, Saratov, 2011

Code Forces で開催された 「School Regional Team Contest, Saratov, 2011」に参加してきました。
しょうもないミスでCまでしか解けていません。


Problem A
Elevator
Passed System Test
簡単という比喩ではなく本当にやるだけ。
School Contestなので、慣れない人たち向けのウォーミングアップ問題の意味合いで設けたのでしょう。


Problem B
Quiz League
Passed System Test
ランダム選択式クイズリーグの途中である。
全部でN問問題が存在し、既に幾つかの問題が解かれている。
今、問題が1〜N番目の中からランダムに選択されようとしているが、既に解かれてしまった問題が選択された場合、その次の問題を解くことになる。それも解かれていた場合、同じことを繰り返す。
N番目の次の問題は、1番目の問題とみなす。


K番目の問題が選ばれたとして、実際に解くことになるのは何番目の問題か。


1行目にN K、
2行目にはN個の0か1かの数字が入力されており、0であれば既に解かれている。


解法


やるだけ。
#include <string>
#include <iostream>
#include <algorithm>
#include <queue>
#include <map>
#include <vector>
#include <set>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <fstream>

using namespace std;

#define REP(i,s,e) for(int i = s;i < e;i++)
#define rep(i,e) REP(i,0,e)
#define ll long long

int main(){
    ifstream input("input.txt");
    ofstream output("output.txt");
    int yet[1000];
    int n,m;
    input >> n >> m;
    rep(i,n) input >> yet[i];
    for(int i = m-1;i < m+n;i++){
        if(yet[i%n]){
            output << (i)%n + 1 << endl;
            return 0;
        }
    }
}


Problem C
Winnie-the-Pooh and Honey
Passed System Test


問題文
ハチミツの入ったつぼがN個ある。
それぞれのつぼにはAi キログラムのハチミツが入っている。
プーさんは飢えており、つぼを取っては、そのつぼに入っているハチミツをKキロ食べる。
選んだつぼに入っているハチミツがKキロ未満の場合か、既にそのつぼから3Kキロ食べていた場合、そのつぼをピグレットに渡す。
この操作を、つぼをピグレットに全て渡すまで繰り返す。
ピグレットは合計で何キロのハチミツを得ることが出来るか?

解法
やるだけ。問題文には、実はハチミツの一番多く入っているつぼを常に食べると書いてあるのですが、これは解法には全く関係しないため、省略しました。


#include <string>
#include <iostream>
#include <algorithm>
#include <queue>
#include <map>
#include <vector>
#include <set>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <fstream>

using namespace std;

#define REP(i,s,e) for(int i = s;i < e;i++)
#define rep(i,e) REP(i,0,e)
#define ll long long
#define INF 1 << 30

int main(){
    ifstream input("input.txt");
    ofstream output("output.txt");
    int jars[100];
    memset(jars, 50000, sizeof(jars));
    int n,k;
    int ans = 0;
    input >> n >> k;
    int limit = k * 3;
    rep(i,n) input >> jars[i];
    sort(jars, jars+99);
    rep(i,n){
        if(jars[i] < limit) ans += jars[i] % k; else ans += jars[i] - limit;
    }
    output << ans << endl;
}
Problem D
Three sons
Wrong Answer on Pretest 3


n*m行列が与えられる。行列のij要素はそれぞれの領域におけるとうもろこしの収量を表す。
この畑を、互いに平行な2本の線を引くことで3つに分割し、それぞれの畑の収量がA,B,Cとなるように分割する方法は何通りあるか?なお、畑は斜めに斬ってはならず、それぞれの畑は最低でも1つの領域を持っていなければならないとする。


ソート関数のメモリ指定を間違えるというポカをやらかした挙句、それに気付かず、ロジック部分に問題があると思い込んで粗を探していました。
終了後に気付き、落ち込む。

解法はnext_permutationを使った至って単純な全探索でした。
データセットが非常に軽いため(最大でも50*50行列)、全探索でも何の問題もありません。


Rating 1446 → 1420 (-26)

少し落ちてしまいました。D問題が解けて入れば、少しはマシだったかもしれませんが、今更嘆いても仕方がありません。
精進あるのみですね。

2011年10月2日日曜日

CaBoCha on Ubuntu 11.04 with charset UTF-8

構文解析器CabochaをUbuntuに実行する際、詰まった点がそこそこあったので、メモしておく。
特に後半に関してはWebでエラーログを検索しても情報がほとんど無かったため、手探り感があった。
Cabochaのインストールそのものについては、他にたくさんのBlogが存在しているので、それについては省く。
このブログに辿り着いた人は多分、
param.cpp(70) [ifs] no such file or directory: /etc/cabocharc
こういうログか、あるいは
morph.cpp(108) [charset() == decode_charset(dinfo->charset)] Incompatible charset: MeCab charset is UTF-8, Your charset is EUCJP-WIN
こういうログで困っているのだろう、と推測する。
まず前者であるが、これはもうエラーログ通り /etc/cabocharc が存在していないことがエラーの原因だ。

sudo find / -name cabocharc

としてやると、おそらく、

/usr/local/etc/cabocharc

というものが見つかる筈だ。
これを

 /etc/cabocharc

にコピーしてやればよい。
次に後者である。
これは、 charset-file.txt に書いてある文字コードと、cabocha の文字コードが一致していないことによって生じている。

sudo find / -name charaset-file.txt

としてやり、セッティングファイルを探す。
いくつか出てくるかもしれないし、一つかもしれない。
それは色々な場合があるので分からないが、そのうちの一つがUTF-8になっていることを確認し(無ければ編集し)する。
次に、先ほどコピーしてやったcabocharcを開く。
コメントアウトされた charaset-filr = PATH という行が見つかる筈だ。
コメントアウトを解除し、先ほどUTF-8と書いてあったファイルへのPATHを記入し、保存してやる。
これで、問題なく動くようになるはずだ。

2011年10月1日土曜日

GCJJ

GCJJに行ってきた。
起きたのが17:50ぐらい。
とりあえず軽くメシ食って、始めたのが18:20分ちょい前ぐらいだったか。

時間がヤバ過ぎたので正解率の高いCを選択。

正の整数Nを、0以上の整数であるa と b を使い

a + b = N

と表す。
f(x)を、xを二進数で表した場合の1の数とし、

f(a) + f(b) = k

のkが最大になる場合のkの値を求めよ。

という問題。
例えば、9ならば、

f(9) + f(0) = 2
f(8) + f(1) = 3
f(7) + f(2) = 4
f(6) + f(3) = 4
f(5) + f(4) = 3

と、それぞれなるので、正解は4となる。

初めは愚直に探索していくのかなと思ったが、largeの制約が N < 10^18だったため、どう考えてもそれでは間に合わない。
二進数ならではの考え方がある。
ビット単位で考えてやると、 10 < 2^4であるから、最大でも4*18 = 72より少ない計算量で達成出来る。

a + b の形になっているので、二進数の特質が大いに生かせそうだ。

暫く考えていたところ、0がキーになっていることが分かった。
11100100111のような場合、右から考えてやって、最初に0が出るまでの1は、aかbどちらかの該当ビットだけに1を設定してやることによってしか表現出来ないが、それ以降の1は、aとbの両方の該当ビット一つ下に1を設定してやることで表現出来そうだ。
これを拡張して、1001001のように0が続いている場合、a = 0111111, b = 0001010 のように表現できることが分かる。

これを実装したのが以下

#include <algorithm>
#include <iostream>
#include <map>
#include <numeric>
#include <set>
#include <sstream>
#include <string>
#include <vector>
#include <stack>
#include <queue>
#include <cmath>
#include <time.h>
using namespace std;

#define REP(i,s,e) for (int i = int(s); i != int(e); i++)
#define rep(i,e) REP(i,0,e)
#define foreach(i,c) for (typeof((c).begin()) i = (c).begin(); i != (c).end(); i++)
#define ISEQ(c) (c).begin(), (c).end()
#define ll long long
#define INF 1<<30



int main(){
 unsigned ll n;
 int testCase,bits_after_zero,bits_before_zero,num_zero;
 scanf("%d", &testCase);
 rep(i,testCase)
 {
  bits_after_zero = 0; bits_before_zero = 0; num_zero = 0;
  scanf("%lld", &n);
  do{
   if(n & 1) bits_before_zero++; else{
    n >>= 1;
    break;
   }
  }while( (n >>= 1) > 0);
  do{
   if(!(n > 0)) break;
   if(n & 1) bits_after_zero++; else num_zero++;
  }while( ( n >>= 1 ) > 0);
  printf("Case #%d: %d\n", i+1, bits_after_zero * 2 + bits_before_zero + num_zero);
 }
}
残りの問題は後でまた解く

2011年9月18日日曜日

Pythonスクリプトの実行時間をメソッドごとに評価する「Python-profiler」が凄い」

Hacker Newsに上がっていた記事「Run,Python,Run!」で扱っているスクリプト、Python Profilerが凄い。

何が凄いって、Pythonでかかれたスクリプトの実行時間を、メソッドごとに計測し、グラフィカルに表示してくれるのだ。

試しに使ってみたが、これは素晴らしかった。

#vim encoding=utf8
def loop(x):
    for i in range(x):
        print "やっほー"

def loop_list(x):
    yahho = []
    for i in range(x):
        yahho.append("やっほー")

yahhoi = loop_list(1000)
loop(1000)

上記のスクリプトを実行し、プロファイルしてみたのが以下


loopが時間を食っていること、更に、loop_list内で実行されているappend()の実行にどれだけ時間を食っているかも分かるのだ。
ちなみにこれ、モジュール内で更に関数を実行していた場合、再帰的に実行時間を計測出来る。
例えば、関数内でurllibのurlopenを実行していた場合、urlopen内で実行されているsocketオブジェクトのメソッドであるconnect_ofの実行時間を計測出来たりもする。
更に深いところになるとまた違う手法を求められるのであろうが(筆者にその知識はない)、しかし、手掛かりを簡単に掴めるというだけでも、使ってみる価値はあるのではなかろうか。

では、インストール方法の説明である。

コンソールに行き、

sudo apt-get install python-profiler python-wxgtk2.8 python-setuptools
sudo easy_install SquareMap RunSnakeRun

たったこれだけだ。

プロファイルの作成方法であるが、

python -m cProfile -o outputfilename  pythonscript script_arguments

こちらのフォーマットに従ってくれれば問題ない。
筆者の行った例で言えば、計測したいスクリプト名が「test.py」、出力したいプロファイル名が「output」であったから、

python -m cProfile -o output test.py

と、した。
プロファイルを見る場合は、

runsnake output

とすればよい。
日頃行っているサービスのパフォーマンス改善は勿論のこと、競技プログラミングで手詰まりを起こした際にも役立つ場面がある(?)のではなかろうか。

2011年7月14日木曜日

CodeForces Beta Round #76 Div2 Only

A
Restoring Password
日本語でおk

B
Friends
Passed System Test


5人の人間が居て、誰と誰が知り合いか、という情報が与えられる。
知り合い同士の3人グループが存在するか、互いに全く知り合いでない3人グループが存在する場合 WIN と、そうでない場合 FAIL と出力せよ

解法
やるだけ

#include <iostream>
#include <vector>
#include <string>
#include <string.h>
#include <map>
#include <set>
#include <algorithm>
#include <time.h>
#include <cmath>
#include <queue>

#define REP(i,s,e) for(int i = s;i<e;i++)
#define rep(i,e) REP(i,0,e)

using namespace std;


int main(){
    int pair[6][6];
    memset(pair,0,sizeof(pair));
    int n;
    cin>>n;
    int a,b;
    rep(i,n){
        cin>>a>>b;

        pair[a][b] = 1;
        pair[b][a] = 1;
    }
    int count[2];
    REP(i,1,6){
        memset(count,0,sizeof(count));
        REP(j,1,6){
            if(i==j) continue;
            if(pair[i][j]) count[0]++; else count[1]++;
        }
        if(count[0] >= 3 || count[1] >= 3){
            cout << "WIN" << endl;
            return 0;
        }
    }
    cout << "FAIL" << endl;

}

Problem C
Frames
Passed System Test


PC上にあるディレクトリ削除の問題
全部n個のフォルダが、m列まで並べられる空間に並べられている。

11個のフォルダを3列に並べる場合

1 2 3
4 5 6
7 8 9
10 11

こんな感じ

a番目からb番目にあるフォルダを全て削除したい。
Shiftキーを押しながら選択することで、複数のフォルダからなる矩形を作成することが出来、矩形に含まれるフォルダは一度に削除することが可能。
全て削除するまでに、何回の操作が必要か?

解法
やるだけ。と言いたいところだが。
前提条件から、操作回数は3以下。
そして、削除すべきフォルダの存在する行数が3以上の場合、考慮すべき問題は全て3
行の時と変わらなくなる。
後は考えられる条件を全て挙げていけば良い。

コード


#include <iostream>
#include <vector>
#include <string>
#include <string.h>
#include <map>
#include <set>
#include <algorithm>
#include <time.h>
#include <cmath>
#include <queue>

#define REP(i,s,e) for(int i = s;i<e;i++)
#define rep(i,e) REP(i,0,e)
#define ll long long

using namespace std;

int main(){
    ll n,m,a,b;
    cin>>n>>m>>a>>b;
    ll column = (b-1)/m - (a-1)/m;
    ll row_a = a%m;
    ll row_b = b%m;
    if(m == 1){
        cout << 1 << endl;
        return 0;
    }
    switch(column){
    case 0:
        cout << 1 << endl; // 一行で済む場合
        return 0;
    case 1:
        if(row_a == 1 && (row_b == 0 || n == b)){ // 二行だが、一回で囲えてしまう場合
            cout << 1 << endl;
            return 0;
        }
        cout << 2 << endl; // そうではない場合
        return 0;

    default: // 三行以上の場合
        if(row_a == 1 && (row_b == 0 || n==b)){ // 一回で全て囲えてしまう場合
            cout << "1" << endl;
            return 0;
        }else if( (a-1)%m == b%m || row_b == 0 || row_a == 1 || b == n){ //
            cout << 2 << endl;
            return 0;
        }
        cout << 3 << endl;
        return 0;
    }


}

Rating 1367 → 1483
かなり上昇しました。
あと、Wrong Answerの場合、正解した時に取得出来るスコアが減少するということを知りました。
次から気を付けてやりたいと思います。

最近は時間が合わず、コンピティションになかなか参加出来ていません。
上手く時間を作って行きたいものです

社会科学×テキストマイニングに役立ちそう(?)な論文

卒業論文で社会科学とテキストマイニングを融合させたものを書こうと思っているので、そのための参考資料をGoogle Scholarで探してみました。
自分はまだ自然言語処理のための理論を学んでいる途中ではありますが、後々必要になると思うので、自分用のメモに。


blog ページの自動収集と監視に基づくテキストマイニング
http://pricai-02.nii.ac.jp/papers/SIG-SWO-A401/SIG-SWO-A401-01.pdf

追記:上記はblogWatcherというサービスに関する文書で、論文というよりも報告書に近い模様。私の立場(情報知能に興味のある経済学部生)からは余り見る価値はなかった。

テキストマイニングによる評価表現の収集
http://www.syncha.org/papers/signl154.pdf

追記:テキストマイニングにおける概念抽出の前段階となる辞書の作成に役立ちそうな論文。
「テキストマイニングを使う技術/作る技術」に載っている手法を用いた方が良いか、こちらが良いかはやってみないと分からん。


Weblog を対象とした評価表現抽
http://www.jaist.ac.jp/ks/labs/kbs-lab/sig-swo/papers/SIG-SWO-A401/SIG-SWO-A401-02.pdf


テキストを対象とした評価情報の分析に関する研究動
http://www.nlp.mibel.cs.tsukuba.ac.jp/~inui/paper/nlp2006-survey.pdf

人口市場とテキストマイニングの融合による市場分析
http://www.ymatsuo.com/papers/jsai07kiyoshi.pdf

2011年7月13日水曜日

自分用メモ

確率を勉強し始めたのでメモ

ポアソン分布
単位時間中にある事象が平均でλ回発生している(前提)

では、単位時間中に事象がk回発生する確率はいくらか?

P(X=k) = (λ^^k*e^^-λ)/k!

これがポアソン分布

exp(x) = e^^x