Problem:
問題文
ふたりのプレイヤーがゲームをしている。以下、ゲームのルールを説明する。
$N×N$ マスのボードがあり、各マスには数字 $X_{i,j}$ ($1 \leq i,j \leq N$)が書かれている。先手と後手は交互に手を選んで点を積み重ねてゆく。最初に先手は $F$ 点持っており、後手は $0$ 点持っている。
$t$ ターン目($1 \leq t \leq 2N$)のプレイヤーの行動を示す。
これ以降自分と相手がどのような手を選んだとしても自分が負けてしまう場合、即座に負けを宣言してゲームを終了する。
これまでに自分が一度も選んだことのない数字を $1,2,...,N$ から一つ選んで $Y_t$ とする。
先手の手番(つまり $t$ が奇数)かつ $t>1$ のとき、先手は $X_{Y_{t}, Y_{t-1}}$ 点を得る。 $t=1$ のとき、先手の得点に変化は起きない。
後手の手番(つまり $t$ が偶数)のとき、後手は $X_{Y_{t-1}, Y_{t}}$ 点を得る。
$t=2N$ のとき、勝敗判定を行いゲームを終了する。点を多く獲得しているプレイヤーの勝ちで、点が同じ場合は引き分けとする。
ターンを終了して相手に手番を渡す。
先手と後手は以下の基準で手を選ぶ。
自分が勝ちになる手が存在するときはその手を選ぶ。自分が勝ちになる手が複数存在するときはその中からゲームが最短で終了するような手を選ぶ。
自分が勝ちになる手が存在しないとき、引き分けになる手が存在すればその手を選ぶ。
自分が負けになる手しか存在しないとき、ゲームが最長で終了するような手を選ぶ。
先手と後手がこのような基準で手を選んだとき、ゲームの結果とゲームが何ターンで終了するかを求めよ。
入力
入力は以下の形式に従う。与えられる数は全て整数である。
$N$ $F$
$X_{1,1}$ $X_{1,2}$ $...$ $X_{1,N}$
$X_{2,1}$ $X_{2,2}$ $...$ $X_{2,N}$
$...$
$X_{N,1}$ $X_{N,2}$ $...$ $X_{N,N}$
制約
$1 \leq N \leq 8$
$-10^5 \leq F \leq 10^5$
$-10^5 \leq X_{i,j} \leq 10^5$
出力
先手が勝つ場合は"First"、後手が勝つ場合は"Second"、引き分けになる場合は"Draw"と1行目に出力せよ。
2行目にゲームが終了するのが何ターン目になるのかを出力せよ。
Sample Input 1
2 0
1 3
1 1
Output for the Sample Input 1
Second
3
Sample Input 2
2 100
0 0
0 0
Output for the Sample Input 2
First
2
Sample Input 3
2 5
3 4
7 6
Output for the Sample Input 3
Draw
4
両者が最善を尽くした場合 $(Y_1,Y_2,Y_3,Y_4) = (1,2,2,1)$ となり、このとき両者11点を獲得して引き分けになる。

Submitted solutions:

code_snippet: #include<bits/stdc++.h>
using namespace std;

#define int long long

#define rep(i,n) for(int i=0;i<(n);i++)
#define pb push_back
#define all(v) (v).begin(),(v).end()
#define fi first
#define se second
typedef vector<int>vint;
typedef pair<int,int>pint;
typedef vector<pint>vpint;

template<typename A,typename B>inline void chmin(A &a,B b){if(a>b)a=b;}
template<typename A,typename B>inline void chmax(A &a,B b){if(a<b)a=b;}

const int UKU=LLONG_MAX/2;
const int INF=1001001001001001001ll;

int N,F;
int X[10][10];

int M[1<<8][1<<8][8];
int m[1<<8][1<<8][8];
int dp[1<<8][1<<8][8];
int calcM(int b,int bb,int pr,int t){
    int &ret=M[b][bb][pr];
    if(ret!=UKU)return ret;
    ret=-INF;
    if(t==2*N+1){
        ret=0;
    }
    else if(t&1){
        rep(i,N){
            if(b>>i&1)continue;
            int tmp=calcM(b|(1<<i),bb,i,t+1);
            if(t!=1)tmp+=X[i][pr];
            chmax(ret,tmp);
        }
    }
    else{
        rep(i,N){
            if(bb>>i&1)continue;
            int tmp=calcM(b,bb|(1<<i),i,t+1);
            tmp-=X[pr][i];
            chmax(ret,tmp);
        }
    }
    return ret;
}

int calcm(int b,int bb,int pr,int t){
    int &ret=m[b][bb][pr];
    if(ret!=UKU)return ret;
    ret=INF;
    if(t==2*N+1){
        ret=0;
    }
    else if(t&1){
        rep(i,N){
            if(b>>i&1)continue;
            int tmp=calcm(b|(1<<i),bb,i,t+1);
            if(t!=1)tmp+=X[i][pr];
            chmin(ret,tmp);
        }
    }
    else{
        rep(i,N){
            if(bb>>i&1)continue;
            int tmp=calcm(b,bb|(1<<i),i,t+1);
            tmp-=X[pr][i];
            chmin(ret,tmp);
        }
    }
    return ret;
}


int calcdp(int b,int bb,int pr,int t){
    int &ret=dp[b][bb][pr];
    if(ret!=UKU)return ret;
    if(t==2*N+1){
        ret=0;
    }
    else if(t&1){
        ret=-INF;
        rep(i,N){
            if(b>>i&1)continue;
            int tmp=calcdp(b|(1<<i),bb,i,t+1);
            if(t!=1)tmp+=X[i][pr];
            chmax(ret,tmp);
        }
    }
    else{
        ret=INF;
        rep(i,N){
            if(bb>>i&1)continue;
            int tmp=calcdp(b,bb|(1<<i),i,t+1);
            tmp-=X[pr][i];
            chmin(ret,tmp);
        }
    }
    return ret;
}

int ei[1<<8][1<<8][8];

int latte(int b,int bb,int pr,int t,int tx){
    if(t==tx){
        if(tx&1)return -M[b][bb][pr];
        return -m[b][bb][pr];
    }
    int &ret=ei[b][bb][pr];
    if(ret!=UKU)return ret;

    if(t&1){
        ret=INF;
        rep(i,N){
            if(b>>i&1)continue;
            int tmp=latte(b|(1<<i),bb,i,t+1,tx);
            if(t!=1)tmp-=X[i][pr];
            chmin(ret,tmp);
        }
    }
    else{
        ret=-INF;
        rep(i,N){
            if(bb>>i&1)continue;
            int tmp=latte(b,bb|(1<<i),i,t+1,tx);
            tmp+=X[pr][i];
            chmax(ret,tmp);
        }
    }
    return ret;
}


signed main(){
    N=8;F=0;
    cin>>N>>F;
    rep(i,N)rep(j,N)cin>>X[i][j];

    fill_n(**M,(1<<8)*(1<<8)*8,UKU);
    fill_n(**m,(1<<8)*(1<<8)*8,UKU);
    fill_n(**dp,(1<<8)*(1<<8)*8,UKU);

    calcM(0,0,0,1);
    calcm(0,0,0,1);
    calcdp(0,0,0,1);

    if(dp[0][0][0]+F==0){
        cout<<"Draw"<<endl;
        cout<<2*N<<endl;
        return 0;
    }

    if(dp[0][0][0]+F>0){
        cout<<"First"<<endl;
        for(int i=2;i<=2*N;i+=2){
            fill_n(**ei,(1<<8)*(1<<8)*8,UKU);
            if(latte(0,0,0,1,i)<F){
                cout<<i<<endl;
                return 0;
            }
        }
    }
    else{
        cout<<"Second"<<endl;
        for(int i=1;i<=2*N;i+=2){
            fill_n(**ei,(1<<8)*(1<<8)*8,UKU);
            if(latte(0,0,0,1,i)>F){
                cout<<i<<endl;
                return 0;
            }
        }
    }

    return 0;
}
accuracy: 1
time_ms: 40
memory_kb: 19524
final_rank: 1

code_snippet: #include<iostream>
#include<cassert>
#include<cmath>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)
const int N = 8;
const int inf = 30000000;
int fp;
int dp[3][1<<N][1<<N][N];
int bit[1<<N];
int m[N][N];
int end;

inline int getPoint(int who,int i,int last){
  if (who == -1)return fp;
  if (who == 0)return m[i][last];
  return m[last][i];
}

/*
  お互いにベストを尽くした時の結果の差を求める。
  初手 -1,
  st1の人、   0
  st2の人、   1
 */
int solve(int n,int iswin,int st1,int st2,int last){
  if (st1 == end && st1 == st2){
    return 0;
  }
  int &ret = dp[iswin][st1][st2][last];
  if (ret != -inf)return ret;

  int who = (bit[st1] == bit[st2])?0:1;
  if (st1 == 0 && st2 == 0)who = -1;
  int nextiswin = iswin==2?2:1^iswin;/*2,1なら勝てるように戦う、0なら負けるように戦う*/
  if (iswin == 1 || iswin == 2)ret = -inf;
  else ret = inf;
  rep(i,n){
    int nextst1=st1,nextst2=st2;
    if (who == 0 || who == -1){//先手
      if (st1&(1<<i))continue;
      nextst1 |= (1<<i);
    }else{
      if (st2&(1<<i))continue;
      nextst2 |= (1<<i);
    }
    int point = getPoint(who,i,last);
    if (iswin == 0){/*負けるなら点差が最小になるように*/
      ret = min(ret,point-solve(n,nextiswin,nextst1,nextst2,i));
    }else {/*勝つなら、点差が最大になるように。*/
      ret = max(ret,point-solve(n,nextiswin,nextst1,nextst2,i));
    }
  }
  return ret;
}

/*
自分が本気、相手が負けるようにやっても勝てないならば、どうやっても勝てない
  初手 -1,
  st1の人、   0
  st2の人、   1
*/
int search(int n,int iswin,int st1,int st2,int last,int diff,int alpha,int beta){
  int turn = bit[st1] + bit[st2];
  if (st1 == end && st1 == st2){
    return turn;
  }
  if (diff + solve(n,1,st1,st2,last) < 0)return turn + 1;/*どう頑張っても負ける場合、ここで打ち切る。*/
  int ret;
  if (iswin)ret = inf;//勝つなら、最小手数を探す
  else ret = -inf;//負けるなら、最大になる手数を選ぶ。
  int who = bit[st1] == bit[st2]?0:1;
  if (st1 == 0 && st2 == 0)who = -1;
  int nextwin = 1^iswin;
  rep(i,n){
    int nextst1=st1,nextst2=st2;
    if (who == 0 || who == -1){//先手
      if (st1&(1<<i))continue;
      nextst1 |= (1<<i);
    }else{
      if (st2&(1<<i))continue;
      nextst2 |= (1<<i);
    }
    int point = getPoint(who,i,last);
    if (iswin == 1){/*勝つなら最小の手数を選択する。*/
      if (diff + point - solve(n,2,nextst1,nextst2,i) <= 0)continue;/*負ける手に遷移しないようにする*/
      ret = min(ret,search(n,nextwin,nextst1,nextst2,i,-point-diff,alpha,ret));
      beta = min(ret,beta);
      if (ret <= alpha){
	break;
      }
    }else{/*負けるなら最大の手数を選択する。*/
      ret = max(ret,search(n,nextwin,nextst1,nextst2,i,-point-diff,ret,beta));
      alpha = max(ret,alpha);
      if (ret >= beta){
	break;
      }
    }
  }
  return ret;
}

main(){
  int n;
  rep(i,(1<<N))bit[i] = __builtin_popcount(i);
  while(cin>>n>>fp && n){
    end = (1<<n)-1;
    rep(i,n)rep(j,n)cin>>m[i][j];
    rep(ii,3)rep(i,(1<<n))rep(j,(1<<n))rep(k,n)dp[ii][i][j][k] = -inf;
    int ans = solve(n,2,0,0,0),step;
    if (ans > 0){
      cout << "First" << endl;
      step = search(n,1,0,0,0,0,-inf,inf);
      cout << step << endl;
    }else if (ans < 0){
      cout << "Second" << endl;
      step = search(n,0,0,0,0,0,-inf,inf);
      cout << step << endl;
    }else if (ans == 0){
      cout << "Draw" << endl;
      cout << 2*n << endl;
    }
  }
  return 0;
}
accuracy: 1
time_ms: 440
memory_kb: 7012
final_rank: 2

code_snippet: #include<iostream>
#include<cassert>
#include<cmath>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)
const int N = 8;
const int inf = 30000000;
int fp;
int dp[3][1<<N][1<<N][N];
int bit[1<<N];
int m[N][N];

inline int getPoint(int who,int i,int last){
  if (who == -1)return fp;
  if (who == 0)return m[i][last];
  return m[last][i];
}

/*
  お互いにベストを尽くした時の結果の差を求める。
  初手 -1,
  st1の人、   0
  st2の人、   1
 */
int solve(int n,int iswin,int st1,int st2,int last){
  if (st1 == (1<<n)-1 && st1 == st2){
    return 0;
  }
  int &ret = dp[iswin][st1][st2][last];
  if (ret != -inf)return ret;

  int who = (bit[st1] == bit[st2])?0:1;
  if (st1 == 0 && st2 == 0)who = -1;
  int nextiswin = iswin==2?2:1^iswin;/*2,1なら勝てるように戦う、0なら負けるように戦う*/
  if (iswin == 1 || iswin == 2)ret = -inf;
  else ret = inf;
  rep(i,n){
    int nextst1=st1,nextst2=st2;
    if (who == 0 || who == -1){//先手
      if (st1&(1<<i))continue;
      nextst1 |= (1<<i);
    }else{
      if (st2&(1<<i))continue;
      nextst2 |= (1<<i);
    }
    int point = getPoint(who,i,last);
    if (iswin == 0){/*負けるなら点差が最小になるように*/
      ret = min(ret,point-solve(n,nextiswin,nextst1,nextst2,i));
    }else {/*勝つなら、点差が最大になるように。*/
      ret = max(ret,point-solve(n,nextiswin,nextst1,nextst2,i));
    }
  }
  return ret;
}

/*
自分が本気、相手が負けるようにやっても勝てないならば、どうやっても勝てない
  初手 -1,
  st1の人、   0
  st2の人、   1
*/
int search(int n,int iswin,int st1,int st2,int last,int diff,int alpha,int beta){
  if (st1 == (1<<n)-1 && st1 == st2){
    return 1;
  }
  if (diff + solve(n,1,st1,st2,last) < 0)return 1;/*どう頑張っても負ける場合、ここで打ち切る。*/
  int ret;
  if (iswin)ret = inf;//勝つなら、最小手数を探す
  else ret = -inf;//負けるなら、最大になる手数を選ぶ。
  int who = bit[st1] == bit[st2]?0:1;
  if (st1 == 0 && st2 == 0)who = -1;
  int nextwin = 1^iswin;
  rep(i,n){
    int nextst1=st1,nextst2=st2;
    if (who == 0 || who == -1){//先手
      if (st1&(1<<i))continue;
      nextst1 |= (1<<i);
    }else{
      if (st2&(1<<i))continue;
      nextst2 |= (1<<i);
    }
    int point = getPoint(who,i,last);
    if (iswin == 1){/*勝つなら最小の手数を選択する。*/
      if (diff + point - solve(n,2,nextst1,nextst2,i) <= 0)continue;/*負ける手に遷移しないようにする*/
      ret = min(ret,1+search(n,nextwin,nextst1,nextst2,i,-point-diff,alpha,beta));
      beta = min(ret,beta);
      if (ret <= alpha){
	break;
      }
    }else{/*負けるなら最大の手数を選択する。*/
      ret = max(ret,1+search(n,nextwin,nextst1,nextst2,i,-point-diff,alpha,beta));
      alpha = max(ret,alpha);
      if (ret >= beta){
	break;
      }
    }
  }
  return ret;
}

main(){
  int n;
  rep(i,(1<<N))bit[i] = __builtin_popcount(i);
  while(cin>>n>>fp && n){
    rep(i,n)rep(j,n)cin>>m[i][j];
    rep(ii,3)rep(i,(1<<n))rep(j,(1<<n))rep(k,n)dp[ii][i][j][k] = -inf;
    int ans = solve(n,2,0,0,0),step;/*お互いに別を尽くした時のスコアを求める。ここから*/
    if (ans > 0){
      cout << "First" << endl;
      step = search(n,1,0,0,0,0,-inf,inf);
      cout << step << endl;
    }else if (ans < 0){
      cout << "Second" << endl;
      step = search(n,0,0,0,0,0,-inf,inf);
      cout << step << endl;
    }else if (ans == 0){
      cout << "Draw" << endl;
      cout << 2*n << endl;
    }
  }
  return 0;
}
accuracy: 0.1346153846153846
time_ms: 50
memory_kb: 7000
final_rank: 5

code_snippet: #include<iostream>
#include<cassert>
#include<cmath>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)
const int N = 8;
const int inf = 30000000;
int fp;
int dp[3][1<<N][1<<N][N];
int bit[1<<N];
int m[N][N];

inline int getPoint(int who,int i,int last){
  if (who == -1)return fp;
  if (who == 0)return m[i][last];
  return m[last][i];
}

/*
  お互いにベストを尽くした時の結果の差を求める。
  初手 -1,
  st1の人、   0
  st2の人、   1
 */
int solve(int n,int iswin,int st1,int st2,int last){
  if (st1 == (1<<n)-1 && st1 == st2){
    return 0;
  }
  int &ret = dp[iswin][st1][st2][last];
  if (ret != -inf)return ret;

  int who = (bit[st1] == bit[st2])?0:1;
  if (st1 == 0 && st2 == 0)who = -1;
  int nextiswin = iswin==2?2:1^iswin;/*2,1なら勝てるように戦う、0なら負けるように戦う*/
  if (iswin == 1 || iswin == 2)ret = -inf;
  else ret = inf;
  rep(i,n){
    int nextst1=st1,nextst2=st2;
    if (who == 0 || who == -1){//先手
      if (st1&(1<<i))continue;
      nextst1 |= (1<<i);
    }else{
      if (st2&(1<<i))continue;
      nextst2 |= (1<<i);
    }
    int point = getPoint(who,i,last);
    if (iswin == 0){/*負けるなら点差が最小になるように*/
      ret = min(ret,point-solve(n,nextiswin,nextst1,nextst2,i));
    }else {/*勝つなら、点差が最大になるように。*/
      ret = max(ret,point-solve(n,nextiswin,nextst1,nextst2,i));
    }
  }
  return ret;
}

/*
自分が本気、相手が負けるようにやっても勝てないならば、どうやっても勝てない
  初手 -1,
  st1の人、   0
  st2の人、   1
*/
int search(int n,int iswin,int st1,int st2,int last,int diff,int alpha,int beta){
  if (st1 == (1<<n)-1 && st1 == st2){
    return 1;
  }
  if (diff + solve(n,1,st1,st2,last) < 0)return 1;/*どう頑張っても負ける場合、ここで打ち切る。*/
  int ret;
  if (iswin)ret = inf;//勝つなら、最小手数を探す
  else ret = -inf;//負けるなら、最大になる手数を選ぶ。
  int who = bit[st1] == bit[st2]?0:1;
  if (st1 == 0 && st2 == 0)who = -1;
  int nextwin = 1^iswin;
  if (beta <= alpha)return 1;
  //if (beta <= bit[st1] + bit[st2])return 1;
  rep(i,n){
    int nextst1=st1,nextst2=st2;
    if (who == 0 || who == -1){//先手
      if (st1&(1<<i))continue;
      nextst1 |= (1<<i);
    }else{
      if (st2&(1<<i))continue;
      nextst2 |= (1<<i);
    }
    int point = getPoint(who,i,last);
    if (iswin == 1){/*勝つなら最小の手数を選択する。*/
      if (diff + point - solve(n,2,nextst1,nextst2,i) <= 0)continue;/*負ける手に遷移しないようにする*/
      ret = min(ret,1+search(n,nextwin,nextst1,nextst2,i,-point-diff,alpha,beta));
      beta = min(ret,beta);
      if (ret <= alpha){
	break;
      }
    }else{/*負けるなら最大の手数を選択する。*/
      ret = max(ret,1+search(n,nextwin,nextst1,nextst2,i,-point-diff,alpha,beta));
      alpha = max(ret,alpha);
      if (ret >= beta){
	break;
      }
    }
  }
  return ret;
}

main(){
  int n;
  rep(i,(1<<N))bit[i] = __builtin_popcount(i);
  while(cin>>n>>fp && n){
    rep(i,n)rep(j,n)cin>>m[i][j];
    rep(ii,3)rep(i,(1<<n))rep(j,(1<<n))rep(k,n)dp[ii][i][j][k] = -inf;
    int ans = solve(n,2,0,0,0),step;/*お互いに別を尽くした時のスコアを求める。ここから*/
    if (ans > 0){
      cout << "First" << endl;
      step = search(n,1,0,0,0,0,-inf,inf);
      cout << step << endl;
    }else if (ans < 0){
      cout << "Second" << endl;
      step = search(n,0,0,0,0,0,-inf,inf);
      cout << step << endl;
    }else if (ans == 0){
      cout << "Draw" << endl;
      cout << 2*n << endl;
    }
  }
  return 0;
}
accuracy: 0.1346153846153846
time_ms: 50
memory_kb: 7000
final_rank: 5

code_snippet: #include<iostream>
#include<cassert>
#include<cmath>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)
const int N = 8;
const int inf = 30000000;
int fp;
int dp[3][1<<N][1<<N][N];
int bit[1<<N];
int m[N][N];

inline int getPoint(int who,int i,int last){
  if (who == -1)return fp;
  if (who == 0)return m[i][last];
  return m[last][i];
}

/*
  お互いにベストを尽くした時の結果の差を求める。
  初手 -1,
  st1の人、   0
  st2の人、   1
 */
int solve(int n,int iswin,int st1,int st2,int last){
  if (st1 == (1<<n)-1 && st1 == st2){
    return 0;
  }
  int &ret = dp[iswin][st1][st2][last];
  if (ret != -inf)return ret;

  int who = (bit[st1] == bit[st2])?0:1;
  if (st1 == 0 && st2 == 0)who = -1;
  int nextiswin = iswin==2?2:1-iswin;/*2,1なら勝てるように戦う、0なら負けるように戦う*/
  if (iswin == 1 || iswin == 2)ret = -inf;
  else ret = inf;
  rep(i,n){
    int nextst1=st1,nextst2=st2;
    if (who == 0 || who == -1){//先手
      if (st1&(1<<i))continue;
      nextst1 |= (1<<i);
    }else{
      if (st2&(1<<i))continue;
      nextst2 |= (1<<i);
    }
    int point = getPoint(who,i,last);
    if (iswin == 0){/*負けるなら点差が最小になるように*/
      ret = min(ret,point-solve(n,nextiswin,nextst1,nextst2,i));
    }else {/*勝つなら、点差が最大になるように。*/
      ret = max(ret,point-solve(n,nextiswin,nextst1,nextst2,i));
    }
  }
  return ret;
}

/*
自分が本気、相手が負けるようにやっても勝てないならば、どうやっても勝てない
  初手 -1,
  st1の人、   0
  st2の人、   1
*/
int search(int n,int iswin,int st1,int st2,int last,int diff,int alpha,int beta){
  int turn = bit[st1] + bit[st2];
  if (st1 == (1<<n)-1 && st1 == st2){
    return 1;
  }
  if (diff + solve(n,1,st1,st2,last) < 0)return 1;/*どう頑張っても負ける場合、ここで打ち切る。*/
  int ret;
  if (iswin)ret = inf;//勝つなら、最小手数を探す
  else ret = -inf;//負けるなら、最大になる手数を選ぶ。
  int who = bit[st1] == bit[st2]?0:1;
  if (st1 == 0 && st2 == 0)who = -1;
  int nextwin = 1-iswin;
  if (beta  < turn + 2)return inf;
  rep(i,n){
    int nextst1=st1,nextst2=st2;
    if (who == 0 || who == -1){//先手
      if (st1&(1<<i))continue;
      nextst1 |= (1<<i);
    }else{
      if (st2&(1<<i))continue;
      nextst2 |= (1<<i);
    }
    int point = getPoint(who,i,last);
    if (iswin == 1){/*勝つなら最小の手数を選択する。*/
      if (diff + point - solve(n,2,nextst1,nextst2,i) <= 0)continue;/*負ける手に遷移しないようにする*/
      ret = min(ret,1+search(n,nextwin,nextst1,nextst2,i,-point-diff,alpha,ret));
      beta = min(ret,beta);
      if (ret <= alpha){
	break;
      }
    }else{/*負けるなら最大の手数を選択する。*/
      ret = max(ret,1+search(n,nextwin,nextst1,nextst2,i,-point-diff,ret,beta));
      alpha = max(ret,alpha);
      if (ret >= beta){
	break;
      }
    }
  }
  return ret;
}

main(){
  int n;
  rep(i,(1<<N))bit[i] = __builtin_popcount(i);
  while(cin>>n>>fp && n){
    rep(i,n)rep(j,n)cin>>m[i][j];
    rep(ii,3)rep(i,(1<<n))rep(j,(1<<n))rep(k,n)dp[ii][i][j][k] = -inf;
    int ans = solve(n,2,0,0,0),step;/*お互いに別を尽くした時のスコアを求める。ここから*/
    if (ans > 0){
      cout << "First" << endl;
      step = search(n,1,0,0,0,0,-inf,inf);
      cout << step << endl;
    }else if (ans < 0){
      cout << "Second" << endl;
      step = search(n,0,0,0,0,0,-inf,inf);
      cout << step << endl;
    }else if (ans == 0){
      cout << "Draw" << endl;
      cout << 2*n << endl;
    }
  }
  return 0;
}
accuracy: 0.15384615384615385
time_ms: 70
memory_kb: 7000
final_rank: 3

code_snippet: #include<iostream>
#include<cassert>
#include<cmath>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)
const int N = 8;
const int inf = 30000000;
int fp;
int dp[3][1<<N][1<<N][N];

int getPoint(int who,int i,int last,const int m[N][N]){
  if (who == -1)return fp;
  if (who == 0)return m[i][last];
  return m[last][i];
}

/*
  お互いにベストを尽くした時の結果の差を求める。
  初手 -1,
  st1の人、   0
  st2の人、   1
 */
int solve(int n,int iswin,int st1,int st2,int last,const int m[N][N]){
  if (st1 == (1<<n)-1 && st1 == st2){
    return 0;
  }
  int who = (__builtin_popcount(st1) == __builtin_popcount(st2))?0:1;
  if (st1 == 0 && st2 == 0)who = -1;
  int &ret = dp[iswin][st1][st2][last];
  if (ret != -inf)return ret;
  int nextiswin = iswin==2?2:1-iswin;/*2,1なら勝てるように戦う、0なら負けるように戦う*/
  if (iswin == 1 || iswin == 2)ret = -inf;
  else ret = inf;

  rep(i,n){
    int nextst1=st1,nextst2=st2;
    if (who == 0 || who == -1){//先手
      if (st1&(1<<i))continue;
      nextst1 |= (1<<i);
    }else{
      if (st2&(1<<i))continue;
      nextst2 |= (1<<i);
    }
    int point = getPoint(who,i,last,m);
    if (iswin == 1 || iswin == 2){/*勝つなら、点差が最大になるように。*/
      ret = max(ret,point-solve(n,nextiswin,nextst1,nextst2,i,m));
    }else {/*負けるなら点差が最小になるように*/
      ret = min(ret,point-solve(n,nextiswin,nextst1,nextst2,i,m));
    }
  }
  return ret;
}

/*
自分が本気、相手が負けるようにやっても勝てないならば、どうやっても勝てない
  初手 -1,
  st1の人、   0
  st2の人、   1
*/
int search(int n,int iswin,int st1,int st2,int last,const int m[N][N],int diff,int alpha,int beta){
  if (st1 == (1<<n)-1 && st1 == st2){
    return 1;
  }
  if (diff + solve(n,1,st1,st2,last,m) < 0)return 1;/*どう頑張っても負ける場合、ここで打ち切る。*/
  int ret;
  if (iswin)ret = inf;//勝つなら、最小手数を探す
  else ret = -inf;//負けるなら、最大になる手数を選ぶ。
  int who = __builtin_popcount(st1) == __builtin_popcount(st2)?0:1;
  if (st1 == 0 && st2 == 0)who = -1;
  int nextwin = 1-iswin;
  rep(i,n){
    int nextst1=st1,nextst2=st2;
    if (who == 0 || who == -1){//先手
      if (st1&(1<<i))continue;
      nextst1 |= (1<<i);
    }else{
      if (st2&(1<<i))continue;
      nextst2 |= (1<<i);
    }
    int point = getPoint(who,i,last,m);
    if (iswin == 1){/*勝つなら最小の手数を選択する。*/
      if (diff + point - solve(n,2,nextst1,nextst2,i,m) <= 0)continue;/*負ける手に遷移しないようにする*/
      ret = min(ret,1+search(n,nextwin,nextst1,nextst2,i,m,-point-diff,alpha,ret));
      beta = min(ret,alpha);
      if (ret <= beta){
	break;
      }
    }else{/*負けるなら最大の手数を選択する。*/
      ret = max(ret,1+search(n,nextwin,nextst1,nextst2,i,m,-point-diff,ret,beta));
      alpha = max(ret,alpha);
      if (ret >= alpha){
	break;
      }
    }
  }
  return ret;
}

main(){
  int n;
  int m[N][N];
  while(cin>>n>>fp && n){
    rep(i,n)rep(j,n)cin>>m[i][j];
    rep(ii,3)rep(i,(1<<n))rep(j,(1<<n))rep(k,n)dp[ii][i][j][k] = -inf;
    int ans = solve(n,2,0,0,0,m),step;/*お互いに別を尽くした時のスコアを求める。ここから*/
    if (ans > 0){
      cout << "First" << endl;
      step = search(n,1,0,0,0,m,0,-inf,inf);
      cout << step << endl;
    }else if (ans < 0){
      cout << "Second" << endl;
      step = search(n,0,0,0,0,m,0,-inf,inf);
      cout << step << endl;
    }else if (ans == 0){
      cout << "Draw" << endl;
      cout << 2*n << endl;
    }
  }
  return 0;
}
accuracy: 0.057692307692307696
time_ms: 40
memory_kb: 0
final_rank: 12

code_snippet: #include<iostream>
#include<cassert>
#include<cmath>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)
const int N = 8;
const int inf = 30000000;
int fp;
int dp[3][1<<N][1<<N][N];

int getPoint(int who,int i,int last,const int m[N][N]){
  if (who == -1)return fp;
  if (who == 0)return m[i][last];
  return m[last][i];
}

/*
  お互いにベストを尽くした時の結果の差を求める。
  初手 -1,
  st1の人、   0
  st2の人、   1
 */
int solve(int n,int iswin,int st1,int st2,int last,const int m[N][N]){
  if (st1 == (1<<n)-1 && st1 == st2){
    return 0;
  }
  int who = (__builtin_popcount(st1) == __builtin_popcount(st2))?0:1;
  if (st1 == 0 && st2 == 0)who = -1;
  int &ret = dp[iswin][st1][st2][last];
  if (ret != -inf)return ret;
  int nextiswin = iswin==2?2:1-iswin;/*2,1なら勝てるように戦う、0なら負けるように戦う*/
  if (iswin == 1 || iswin == 2)ret = -inf;
  else ret = inf;

  rep(i,n){
    int nextst1=st1,nextst2=st2;
    if (who == 0 || who == -1){//先手
      if (st1&(1<<i))continue;
      nextst1 |= (1<<i);
    }else {
      if (st2&(1<<i))continue;
      nextst2 |= (1<<i);
    }
    int point = getPoint(who,i,last,m);
    if (iswin == 1 || iswin == 2){/*勝つなら、点差が最大になるように。*/
      ret = max(ret,point-solve(n,nextiswin,nextst1,nextst2,i,m));
    }else {/*負けるなら点差が最小になるように*/
      ret = min(ret,point-solve(n,nextiswin,nextst1,nextst2,i,m));
    }
  }
  return ret;
}

/*
自分が本気、相手が負けるようにやっても勝てないならば、どうやっても勝てない
  初手 -1,
  st1の人、   0
  st2の人、   1
*/
int search(int n,int iswin,int st1,int st2,int last,const int m[N][N],int diff,int alpha,int beta){
  if (st1 == (1<<n)-1 && st1 == st2){
    return 1;
  }
  if (diff + solve(n,1,st1,st2,last,m) < 0)return 1;/*どう頑張っても勝つことができないとき。ここで打ち切る*/
  int ret;
  if (iswin)ret = inf;//勝つなら、最小手数を探す
  else ret = -inf;//負けるなら、最大になる手数を選ぶ。
  int who = __builtin_popcount(st1) == __builtin_popcount(st2)?0:1;
  if (st1 == 0 && st2 == 0)who = -1;
  int nextwin = 1-iswin;
  rep(i,n){
    int nextst1=st1,nextst2=st2;
    if (who == 0 || who == -1){//先手
      if (st1&(1<<i))continue;
      nextst1 |= (1<<i);
    }else {
      if (st2&(1<<i))continue;
      nextst2 |= (1<<i);
    }
    int point = getPoint(who,i,last,m);
    if (iswin == 1){/*勝つなら最小の手数を選択する。*/
      if (point - solve(n,2,nextst1,nextst2,i,m) < 0)continue;/*負ける手に遷移しないようにする*/
      ret = min(ret,1+search(n,nextwin,nextst1,nextst2,i,m,-point-diff,ret,beta));
      if (ret <= beta){
	break;
      }
    }else {/*負けるなら最大の手数を選択する。*/
      ret = max(ret,1+search(n,nextwin,nextst1,nextst2,i,m,-point-diff,alpha,ret));
      if (ret >= alpha){
	break;
      }
    }
  }
  return ret;
}

main(){
  int n;
  int m[N][N];
  while(cin>>n>>fp && n){
    rep(i,n)rep(j,n)cin>>m[i][j];
    rep(ii,3)rep(i,(1<<n))rep(j,(1<<n))rep(k,n)dp[ii][i][j][k] = -inf;
    int ans = solve(n,2,0,0,0,m),step;/*お互いに別を尽くした時のスコアを求める。ここから*/
    if (ans > 0){
      cout << "First" << endl;
      step = search(n,1,0,0,0,m,0,inf,-inf);
      cout << step << endl;
    }else if (ans < 0){
      cout << "Second" << endl;
      step = search(n,0,0,0,0,m,0,inf,-inf);
      cout << step << endl;
    }else if (ans == 0){
      cout << "Draw" << endl;
      cout << 2*n << endl;
    }
  }
  return 0;
}
accuracy: 0.057692307692307696
time_ms: 490
memory_kb: 0
final_rank: 15

code_snippet: #include<iostream>
#include<cassert>
#include<cmath>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)
const int N = 8;
const int inf = 30000000;
int fp;
int dp[3][1<<N][1<<N][N];

int getPoint(int who,int i,int last,const int m[N][N]){
  if (who == -1)return fp;
  if (who == 0)return m[i][last];
  return m[last][i];
}

/*
  お互いにベストを尽くした時の結果の差を求める。
  初手 -1,
  st1の人、   0
  st2の人、   1
 */
int solve(int n,int iswin,int st1,int st2,int last,const int m[N][N]){
  if (st1 == (1<<n)-1 && st1 == st2){
    return 0;
  }
  int who = (__builtin_popcount(st1) == __builtin_popcount(st2))?0:1;
  if (st1 == 0 && st2 == 0)who = -1;
  int &ret = dp[iswin][st1][st2][last];
  if (ret != -inf)return ret;
  int nextiswin = iswin==2?2:1-iswin;/*2,1なら勝てるように戦う、0なら負けるように戦う*/
  if (iswin == 1 || iswin == 2)ret = -inf;
  else ret = inf;

  rep(i,n){
    int nextst1=st1,nextst2=st2;
    if (who == 0 || who == -1){//先手
      if (st1&(1<<i))continue;
      nextst1 |= (1<<i);
    }else {
      if (st2&(1<<i))continue;
      nextst2 |= (1<<i);
    }
    int point = getPoint(who,i,last,m);
    if (iswin == 1 || iswin == 2){/*勝つなら、点差が最大になるように。*/
      ret = max(ret,point-solve(n,nextiswin,nextst1,nextst2,i,m));
    }else {/*負けるなら点差が最小になるように*/
      ret = min(ret,point-solve(n,nextiswin,nextst1,nextst2,i,m));
    }
  }
  return ret;
}

/*
自分が本気、相手が負けるようにやっても勝てないならば、どうやっても勝てない
  初手 -1,
  st1の人、   0
  st2の人、   1
*/
int search(int n,int iswin,int st1,int st2,int last,const int m[N][N],int diff,int alpha,int beta){
  if (st1 == (1<<n)-1 && st1 == st2){
    return 1;
  }
  if (diff + solve(n,1,st1,st2,last,m) < 0)return 1;/*どう頑張っても勝つことができないとき。ここで打ち切る*/
  int ret;
  if (iswin)ret = inf;//勝つなら、最小手数を探す
  else ret = -inf;//負けるなら、最大になる手数を選ぶ。
  int who = __builtin_popcount(st1) == __builtin_popcount(st2)?0:1;
  if (st1 == 0 && st2 == 0)who = -1;
  int nextwin = 1-iswin;
  rep(i,n){
    int nextst1=st1,nextst2=st2;
    if (who == 0 || who == -1){//先手
      if (st1&(1<<i))continue;
      nextst1 |= (1<<i);
    }else {
      if (st2&(1<<i))continue;
      nextst2 |= (1<<i);
    }
    int point = getPoint(who,i,last,m);
    if (iswin == 1){/*勝つなら最小の手数を選択する。*/
      if (point - solve(n,2,nextst1,nextst2,i,m) <= 0)continue;/*負ける手に遷移しないようにする*/
      ret = min(ret,1+search(n,nextwin,nextst1,nextst2,i,m,-point-diff,ret,beta));
      if (ret <= beta){
	break;
      }
    }else {/*負けるなら最大の手数を選択する。*/
      ret = max(ret,1+search(n,nextwin,nextst1,nextst2,i,m,-point-diff,alpha,ret));
      if (ret >= alpha){
	break;
      }
    }
  }
  return ret;
}

main(){
  int n;
  int m[N][N];
  while(cin>>n>>fp && n){
    rep(i,n)rep(j,n)cin>>m[i][j];
    rep(ii,3)rep(i,(1<<n))rep(j,(1<<n))rep(k,n)dp[ii][i][j][k] = -inf;
    int ans = solve(n,2,0,0,0,m),step;/*お互いに別を尽くした時のスコアを求める。ここから*/
    if (ans > 0){
      cout << "First" << endl;
      step = search(n,1,0,0,0,m,0,inf,-inf);
      cout << step << endl;
    }else if (ans < 0){
      cout << "Second" << endl;
      step = search(n,0,0,0,0,m,0,inf,-inf);
      cout << step << endl;
    }else if (ans == 0){
      cout << "Draw" << endl;
      cout << 2*n << endl;
    }
  }
  return 0;
}
accuracy: 0.057692307692307696
time_ms: 490
memory_kb: 0
final_rank: 15

code_snippet: #include<iostream>
#include<cassert>
#include<cmath>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)
const int N = 8;
const int inf = 30000000;
int fp;
int dp[3][1<<N][1<<N][N];

int getPoint(int who,int i,int last,const int m[N][N]){
  if (who == -1)return fp;
  if (who == 0)return m[i][last];
  return m[last][i];
}

/*
  お互いにベストを尽くした時の結果の差を求める。
  初手 -1,
  st1の人、   0
  st2の人、   1
 */
int solve(int n,int iswin,int st1,int st2,int last,const int m[N][N]){
  if (st1 == (1<<n)-1 && st1 == st2){
    return 0;
  }
  int who = (__builtin_popcount(st1) == __builtin_popcount(st2))?0:1;
  if (st1 == 0 && st2 == 0)who = -1;
  int &ret = dp[iswin][st1][st2][last];
  if (ret != -inf)return ret;
  int nextiswin = iswin==2?2:1-iswin;/*2,1なら勝てるように戦う、0なら負けるように戦う*/
  if (iswin == 1 || iswin == 2)ret = -inf;
  else ret = inf;

  rep(i,n){
    int nextst1=st1,nextst2=st2;
    if (who == 0 || who == -1){//先手
      if (st1&(1<<i))continue;
      nextst1 |= (1<<i);
    }else {
      if (st2&(1<<i))continue;
      nextst2 |= (1<<i);
    }
    int point = getPoint(who,i,last,m);
    if (iswin == 1 || iswin == 2){/*勝つなら、点差が最大になるように。*/
      ret = max(ret,point-solve(n,nextiswin,nextst1,nextst2,i,m));
    }else {/*負けるなら点差が最小になるように*/
      ret = min(ret,point-solve(n,nextiswin,nextst1,nextst2,i,m));
    }
  }
  return ret;
}

/*
自分が本気、相手が負けるようにやっても勝てないならば、どうやっても勝てない
  初手 -1,
  st1の人、   0
  st2の人、   1
*/
int search(int n,int iswin,int st1,int st2,int last,const int m[N][N],int diff,int alpha,int beta){
  if (st1 == (1<<n)-1 && st1 == st2){
    return 0;
  }
  if (diff + solve(n,1,st1,st2,last,m) < 0)return 1;/*どう頑張っても勝つことができないとき。ここで打ち切る*/
  int ret;
  if (iswin)ret = inf;//勝つなら、最小手数を探す
  else ret = -inf;//負けるなら、最大になる手数を選ぶ。
  int who = __builtin_popcount(st1) == __builtin_popcount(st2)?0:1;
  if (st1 == 0 && st2 == 0)who = -1;
  int nextwin = 1-iswin;
  rep(i,n){
    int nextst1=st1,nextst2=st2;
    if (who == 0 || who == -1){//先手
      if (st1&(1<<i))continue;
      nextst1 |= (1<<i);
    }else {
      if (st2&(1<<i))continue;
      nextst2 |= (1<<i);
    }
    int point = getPoint(who,i,last,m);
    if (iswin == 1){/*勝つなら最小の手数を選択する。*/
      if (point - solve(n,2,nextst1,nextst2,i,m) <= 0)continue;/*負ける手に遷移しないようにする*/
      ret = min(ret,1+search(n,nextwin,nextst1,nextst2,i,m,-point-diff,ret,beta));
      if (ret <= beta){
	break;
      }
    }else {/*負けるなら最大の手数を選択する。*/
      ret = max(ret,1+search(n,nextwin,nextst1,nextst2,i,m,-point-diff,alpha,ret));
      if (ret >= alpha){
	break;
      }
    }
  }
  return ret;
}

main(){
  int n;
  int m[N][N];
  while(cin>>n>>fp && n){
    rep(i,n)rep(j,n)cin>>m[i][j];
    rep(ii,3)rep(i,(1<<n))rep(j,(1<<n))rep(k,n)dp[ii][i][j][k] = -inf;
    int ans = solve(n,2,0,0,0,m),step;/*お互いに別を尽くした時のスコアを求める。ここから*/
    if (ans > 0){
      cout << "First" << endl;
      step = search(n,1,0,0,0,m,0,inf,-inf);
      cout << step << endl;
    }else if (ans < 0){
      cout << "Second" << endl;
      step = search(n,0,0,0,0,m,0,inf,-inf);
      cout << step << endl;
    }else if (ans == 0){
      cout << "Draw" << endl;
      cout << 2*n << endl;
    }
  }
  return 0;
}
accuracy: 0.057692307692307696
time_ms: 490
memory_kb: 0
final_rank: 15

code_snippet: #include<iostream>
#include<cassert>
#include<cmath>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)
const int N = 8;
const int inf = 30000000;
int fp;
int dp[3][1<<N][1<<N][N];

int getPoint(int who,int i,int last,const int m[N][N]){
  if (who == -1)return fp;
  if (who == 0)return m[i][last];
  return m[last][i];
}

/*
  お互いにベストを尽くした時の結果の差を求める。
  初手 -1,
  st1の人、   0
  st2の人、   1
 */
int solve(int n,int iswin,int st1,int st2,int last,const int m[N][N]){
  if (st1 == (1<<n)-1 && st1 == st2){
    return 0;
  }
  int who = (__builtin_popcount(st1) == __builtin_popcount(st2))?0:1;
  if (st1 == 0 && st2 == 0)who = -1;
  int &ret = dp[iswin][st1][st2][last];
  if (ret != -inf)return ret;
  int nextiswin = iswin==2?2:1-iswin;/*2,1なら勝てるように戦う、0なら負けるように戦う*/
  if (iswin == 1 || iswin == 2)ret = -inf;
  else ret = inf;

  rep(i,n){
    int nextst1=st1,nextst2=st2;
    if (who == 0 || who == -1){//先手
      if (st1&(1<<i))continue;
      nextst1 |= (1<<i);
    }else {
      if (st2&(1<<i))continue;
      nextst2 |= (1<<i);
    }
    int point = getPoint(who,i,last,m);
    if (iswin == 1 || iswin == 2){/*勝つなら、点差が最大になるように。*/
      ret = max(ret,point-solve(n,nextiswin,nextst1,nextst2,i,m));
    }else {/*負けるなら点差が最小になるように*/
      ret = min(ret,point-solve(n,nextiswin,nextst1,nextst2,i,m));
    }
  }
  return ret;
}

/*
自分が本気、相手が負けるようにやっても勝てないならば、どうやっても勝てない
  初手 -1,
  st1の人、   0
  st2の人、   1
*/
int search(int n,int iswin,int st1,int st2,int last,const int m[N][N],int diff,int alpha,int beta){
  if (st1 == (1<<n)-1 && st1 == st2){
    return 0;
  }
  if (diff + solve(n,1,st1,st2,last,m) < 0)return 1;/*どう頑張っても勝つことができないとき。ここで打ち切る*/
  int ret;
  if (iswin)ret = inf;//勝つなら、最小手数を探す
  else ret = -inf;//負けるなら、最大になる手数を選ぶ。
  int who = __builtin_popcount(st1) == __builtin_popcount(st2)?0:1;
  if (st1 == 0 && st2 == 0)who = -1;
  int nextwin = 1-iswin;
  rep(i,n){
    int nextst1=st1,nextst2=st2;
    if (who == 0 || who == -1){//先手
      if (st1&(1<<i))continue;
      nextst1 |= (1<<i);
    }else {
      if (st2&(1<<i))continue;
      nextst2 |= (1<<i);
    }
    int point = getPoint(who,i,last,m);
    if (iswin == 1){/*勝つなら最小の手数を選択する。*/
      if (point - solve(n,2,nextst1,nextst2,i,m) <= 0)continue;/*負ける手に遷移しないようにする*/
      ret = min(ret,1+search(n,nextwin,nextst1,nextst2,i,m,-point-diff,ret,beta));
      if (ret <= beta){
	break;
      }
    }else {/*負けるなら最大の手数を選択する。*/
      ret = max(ret,1+search(n,nextwin,nextst1,nextst2,i,m,-point-diff,alpha,ret));
      if (ret <= alpha){
	break;
      }
    }
  }
  return ret;
}

main(){
  int n;
  int m[N][N];
  while(cin>>n>>fp && n){
    rep(i,n)rep(j,n)cin>>m[i][j];
    rep(ii,3)rep(i,(1<<n))rep(j,(1<<n))rep(k,n)dp[ii][i][j][k] = -inf;
    int ans = solve(n,2,0,0,0,m),step;/*お互いに別を尽くした時のスコアを求める。ここから*/
    if (ans > 0){
      cout << "First" << endl;
      step = search(n,1,0,0,0,m,0,inf,-inf);
      cout << step << endl;
    }else if (ans < 0){
      cout << "Second" << endl;
      step = search(n,0,0,0,0,m,0,inf,-inf);
      cout << step << endl;
    }else if (ans == 0){
      cout << "Draw" << endl;
      cout << 2*n << endl;
    }
  }
  return 0;
}
accuracy: 0.057692307692307696
time_ms: 50
memory_kb: 0
final_rank: 13

code_snippet: #include<iostream>
#include<cassert>
#include<cmath>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)
const int N = 8;
const int inf = 30000000;
int fp;
int dp[3][1<<N][1<<N][N];

int getPoint(int who,int i,int last,const int m[N][N]){
  if (who == -1)return fp;
  if (who == 0)return m[i][last];
  return m[last][i];
}

/*
  お互いにベストを尽くした時の結果の差を求める。
  初手 -1,
  st1の人、   0
  st2の人、   1
 */
int solve(int n,int iswin,int st1,int st2,int last,const int m[N][N]){
  if (st1 == (1<<n)-1 && st1 == st2){
    return 0;
  }
  int who = (__builtin_popcount(st1) == __builtin_popcount(st2))?0:1;
  if (st1 == 0 && st2 == 0)who = -1;
  int &ret = dp[iswin][st1][st2][last];
  if (ret != -inf)return ret;
  int nextiswin = iswin==2?2:1-iswin;/*2,1なら勝てるように戦う、0なら負けるように戦う*/
  if (iswin == 1 || iswin == 2)ret = -inf;
  else ret = inf;

  rep(i,n){
    int nextst1=st1,nextst2=st2;
    if (who == 0 || who == -1){//先手
      if (st1&(1<<i))continue;
      nextst1 |= (1<<i);
    }else {
      if (st2&(1<<i))continue;
      nextst2 |= (1<<i);
    }
    int point = getPoint(who,i,last,m);
    if (iswin == 1 || iswin == 2){/*勝つなら、点差が最大になるように。*/
      ret = max(ret,point-solve(n,nextiswin,nextst1,nextst2,i,m));
    }else {/*負けるなら点差が最小になるように*/
      ret = min(ret,point-solve(n,nextiswin,nextst1,nextst2,i,m));
    }
  }
  return ret;
}

/*
自分が本気、相手が負けるようにやっても勝てないならば、どうやっても勝てない
  初手 -1,
  st1の人、   0
  st2の人、   1
*/
int search(int n,int iswin,int st1,int st2,int last,const int m[N][N],int diff){
  if (st1 == (1<<n)-1 && st1 == st2){
    return 0;
  }
  if (diff + solve(n,1,st1,st2,last,m) < 0)return 1;/*どう頑張っても勝つことができないとき。ここで打ち切る*/
  int ret;
  if (iswin)ret = inf;//勝つなら、最小手数を探す
  else ret = -inf;//負けるなら、最大になる手数を選ぶ。
  int who = __builtin_popcount(st1) == __builtin_popcount(st2)?0:1;
  if (st1 == 0 && st2 == 0)who = -1;
  int nextwin = 1-iswin;
  rep(i,n){
    int nextst1=st1,nextst2=st2;
    if (who == 0 || who == -1){//先手
      if (st1&(1<<i))continue;
      nextst1 |= (1<<i);
    }else {
      if (st2&(1<<i))continue;
      nextst2 |= (1<<i);
    }
    int point = getPoint(who,i,last,m);
    if (iswin == 1){/*勝つなら最小の手数を選択する。*/
      if (point - solve(n,2,nextst1,nextst2,i,m) <= 0)continue;/*負ける手に遷移しないようにする*/
      ret = min(ret,1+search(n,nextwin,nextst1,nextst2,i,m,-point+diff));
    }else {/*負けるなら最大の手数を選択する。*/
      ret = max(ret,1+search(n,nextwin,nextst1,nextst2,i,m,-point+diff));
    }
  }
  return ret;
}

main(){
  int n;
  int m[N][N];
  while(cin>>n>>fp && n){
    rep(i,n)rep(j,n)cin>>m[i][j];
    rep(ii,3)rep(i,(1<<n))rep(j,(1<<n))rep(k,n)dp[ii][i][j][k] = -inf;
    int ans = solve(n,2,0,0,0,m),step;/*お互いに別を尽くした時のスコアを求める。ここから*/
    if (ans > 0){
      cout << "First" << endl;
      step = search(n,1,0,0,0,m,0);
      cout << step << endl;
    }else if (ans < 0){
      cout << "Second" << endl;
      step = search(n,0,0,0,0,m,0);
      cout << step << endl;
    }else if (ans == 0){
      cout << "Draw" << endl;
      cout << 2*n << endl;
    }
  }
  return 0;
}
accuracy: 0.057692307692307696
time_ms: 100
memory_kb: 0
final_rank: 14

code_snippet: #include<iostream>
#include<cassert>
#include<cmath>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)
const int N = 8;
const int inf = 30000000;
int dp[2][(1<<N)][(1<<N)][N];/*自分の選んだ場所、相手の選んだ場所、最後に選ばれた数字*/

/*
  最高の場合の自分と相手の点数の差を求めておく。
  探索時にこの差、で相手の点数に追いつけなければ負けが確定するので、その時点で打ち切りできるようになる。
  signが0の時は、自分は最善手、相手は最悪手を選ぶ。
  signが1の時は、自分は最悪手、相手は最善手を選ぶ。
*/
int precalc(int n,int sign,int st1,int st2,int last,const int m[N][N]){
  if (st1 == (1<<n)-1 && st1 == st2){
    return dp[sign][st1][st2][last] = 0;
  }
  if (last == -1){/*最初の手*/
    int ret;
    if (sign == 0)ret = -inf;
    else ret = inf;
    rep(i,n){
      int tmp = precalc(n,sign,1<<i,st2,i,m);
      if (sign == 0)ret = max(ret,-tmp);
      else if (sign == 1)ret = min(ret,-tmp);
    }
    return ret;
  }
  int &ret = dp[sign][st1][st2][last];
  if (ret != -inf)return ret;
  if (__builtin_popcount(st1) == __builtin_popcount(st2)){/*次の手は自分*/
    if (sign == 0)ret = -inf;
    else if (sign == 1)ret = inf;
    rep(i,n){
      if ((1<<i)&st1)continue;
      int tmp = precalc(n,sign,st1|(1<<i),st2,i,m);
      if (sign == 0)ret = max(ret,m[i][last] - tmp);
      else if (sign == 1)ret = min(ret,m[i][last]-tmp);
    }
  }else {
    if (sign == 0)ret = inf;
    else if (sign == 1)ret = -inf;
    rep(i,n){
      if ((1<<i)&st2)continue;
      int tmp = precalc(n,sign,st1,st2|(1<<i),i,m);
      if (sign == 0)ret = min(ret,m[last][i] - tmp);
      else if (sign == 1)ret = max(ret,m[last][i] - tmp);
    }
  }
  return ret;
}

/*
  評価値から手数を復元
*/
int getop(const int val){
  int ret = 0;
  if (val == 0){
    ret = val;
  }else if (val > 0){
    ret = val - inf;
  }else if (val < 0){
    ret = inf + val;
    ret *= -1;
  }
  return ret;
}

/*評価値から符号付き手数を復元*/
int getSignedOp(const int val){
  int ret = 0;
  if (val == 0){
    ret = val;
  }else if (val > 0){
    ret = inf - val;
  }else if (val < 0){
    ret = inf + val ;
  }
  return ret;
}

/*符号付き手数から次の符号付き手数を生成する*/
int getNextSignedOp(const int val){
  int ret = 0;
  if (val == 0){
    ret = val;
  }else if (val < 0){
    ret = val;
    ret--;
    ret *= -1;
  }else if (val > 0){
    ret = val;
    ret++;
    ret *= -1;
  }
  return ret;
}

/*
  符号付き手数から次の結果を計算する
*/
int update(const int ret,const int op){
  if (ret == -inf || ret == inf){
    return op;
  }
  if (op == 0){/*引き分け*/
    if (ret > 0)return ret;/*すでに勝つことが決まっているなら答えは変わらない*/
    else return 0;/*負けか引き分けなら引き分け*/
  }else if (op > 0){/*勝ち*/
    if (ret > 0)return min(ret,op);/*すでに勝つことが決まっているなら、最小の手数を返す*/
    else return op;/*負けか引き分けならopを返す*/
  }else if (op < 0){/*負け*/
    if (ret >= 0)return ret;/*価値か引き分けなら答えは変わらない*/
    else return min(ret,op);/*負けなら負けるまでの手数が大きい方を選ぶ*/
  }
  assert(false);
}

/*符号付き手数から評価値を返す*/
int getval(const int op){
  if (op == 0){
    return 0;
  }else if (op > 0){
    return inf - op;
  }else if (op < 0){
    return -(inf - (-op));
  }
  assert(false);
}

/*
  ALPHA-BETAカットを用いた探索を行う。
  評価値は
  勝つときはinf-手数。
  引き分けなら0
  負なら -(inf+手数)
  を評価値として使う（解説通り）

  自分の番、評価値の最大化を目指す。
  相手の番、評価値の最小化を目指す。

  自分の番、親のノードの探索途中の評価値（相手の値）よりでかいものが出てきたとする。
  　　　　　この時、自分の番で選ばれるものを、相手が選ぶことがなくなるので枝刈りできる。
            （相手は最小になる手を選ぶのでここが選ばれることがなくなるのでもう見る必要がない）
  相手の番、親の最大値（自分の値）より小さいものが出てきたら終了。
  　　　　　（自分は、最大の値となるものを選ぶ。相手は最小となるものを選ぶ。このノードから探索を続けても、相手の評価値はより小さい値にしかならず、
  　　　　　　自分の番でこのノードが選ばれることがないのがわかる。

  返り値は評価値。
  内部の計算は手数で行おう。
*/

int acut = 0,bcut = 0;
int search(int n,int st1,int st2,int last,const int m[N][N],int myp,int opp,int alpha,int beta){
  if (st1 == (1<<n)-1 && st1 == st2 ){
    if (myp > opp)return 1;
    else if (myp < opp)return -1;
    return 0;//引き分け
  }
  int ret = -inf;
  if (last == -1){
    rep(i,n){
      int tmp = search(n,(1<<i),st2,i,m,myp,opp,alpha,beta);
      int op = getNextSignedOp(tmp);
      ret = update(ret,op);
      alpha = max(alpha,getval(op));
    }
    return ret;
  }
  if (__builtin_popcount(st1) == __builtin_popcount(st2)){//自分の番、評価値を最大化する。
    if (myp+dp[0][st1][st2][last] < opp)return -1;//負け
    rep(i,n){
      if ((1<<i)&st1)continue;
      int tmp=search(n,st1|(1<<i),st2,i,m,myp+m[i][last],opp,alpha,beta);
      int op = getNextSignedOp(tmp);
      if (getval(tmp) > alpha)ret = update(ret,op);
      alpha = max(alpha,getval(tmp));
      if (alpha > beta){
	bcut++;
	break;
      }
    }
  }else {//相手の番、評価値を最小化する。
    if (myp > opp+dp[1][st1][st2][last])return -1;//負けが確定しているのでゲームを終了する
    rep(i,n){
      if ((1<<i)&st2)continue;
      int tmp=search(n,st1,st2|(1<<i),i,m,myp,opp+m[last][i],alpha,beta);
      int op = getNextSignedOp(tmp);
      if (getval(tmp) < beta)ret = update(ret,op);
      beta = min(beta,getval(tmp));
      if (alpha > beta){
	acut++;
	break;
      }
    }
  }
  return ret;
}


/*
  勝ち    1
  引き分け0
  負け　　-1
*/
short dpDebug[(1<<N)][(1<<N)][(1<<N)];
short searchDebug(int n,int st1,int st2,int last,const int m[N][N],int myp,int opp,int alpha,int beta){
  if (st1 == (1<<n)-1 && st1 == st2 ){
    assert(myp == opp);
    return 0;//引き分け
  }
  if (last == -1){
    int ret = -1;
    rep(i,n){
      int tmp = searchDebug(n,(1<<i),st2,i,m,myp,opp,alpha,beta);
      if (tmp == -1)return 1;
      else if (tmp == 0)ret = 0;
    }
    return ret;
  }
  short &ret = dpDebug[st1][st2][last];
  if (ret != -2)return ret;
  ret = -1;
  if (__builtin_popcount(st1) == __builtin_popcount(st2)){//自分の番、評価値を最大化する。
    if (myp+dp[0][st1][st2][last] < opp)return -1;//負け
    rep(i,n){
    if ((1<<i)&st1)continue;
      int tmp=searchDebug(n,st1|(1<<i),st2,i,m,myp+m[i][last],opp,alpha,beta);
      if (tmp == -1)return 1;
      else if (tmp == 0)ret = 0;
    }
  }else {//相手の番、評価値を最小化する。
    if (myp > opp+dp[1][st1][st2][last])return -1;//負けが確定しているのでゲームを終了する
    rep(i,n){
      if ((1<<i)&st2)continue;
      int tmp=searchDebug(n,st1,st2|(1<<i),i,m,myp,opp+m[last][i],alpha,beta);
      if (tmp == -1)return 1;
      else if (tmp == 0)ret = 0;
    }
  }
  return ret;
}

main(){
  int n;
  int m[N][N];
  int f;
  while(cin>>n>>f && n){
    rep(i,n)rep(j,n)cin>>m[i][j];
    rep(ii,2)rep(i,(1<<n))rep(j,(1<<n))rep(k,n)dp[ii][i][j][k] = -inf;
    rep(i,(1<<n))rep(j,(1<<n))rep(k,n)dpDebug[i][j][k] = -2;
    int tmp = precalc(n,0,0,0,-1,m);
    int tmp2 = precalc(n,1,0,0,-1,m);
    if (tmp + f < 0){//特殊ケース、先手の人はどうやっても勝てない
      cout << "Second" << endl;
      cout << 1 << endl;
      continue;
    }
    
    //int ans = search(n,0,0,-1,m,f,0,-inf/2,inf/2);/*alpha,betaは後でp適切な値に修正すること。*/
    int ans   = search(     n,0,0,-1,m,f,0,-2*inf,2*inf);/*alpha,betaは後でp適切な値に修正すること。*/
    short check = searchDebug(n,0,0,-1,m,f,0,   0,  0);
    //cout <<"check " << ans <<" " << check << endl;
    if (ans == 0){
      assert(check == 0);
      cout << "Draw" << endl;
      cout << 2*n << endl;//引き分けならあきらかに2N手かかる
    }else if (ans > 0){
      assert(check == 1);
      cout << "First" << endl;
      //cout << getop(ans) << endl;
      //cout << -ans << endl;
      cout << ans << endl;
    }else if (ans < 0){
      assert(check == -1);
      cout << "Second" << endl;
      //cout << getop(ans) << endl;
      cout << -ans << endl;
    }

#ifdef DEBUG
    cout << "--------------debug" <<endl;
    cout << acut << " " << bcut << endl;
    cout << "----------------end" << endl;
#endif
  }
  return 0;
}
accuracy: 0.057692307692307696
time_ms: 40
memory_kb: 36000
final_rank: 18

code_snippet: #include<iostream>
#include<cassert>
#include<cmath>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)
const int N = 8;
const int inf = 30000000;
int dp[2][(1<<N)][(1<<N)][N];/*自分の選んだ場所、相手の選んだ場所、最後に選ばれた数字*/

/*
  最高の場合の自分と相手の点数の差を求めておく。
  探索時にこの差、で相手の点数に追いつけなければ負けが確定するので、その時点で打ち切りできるようになる。
  signが0の時は、自分は最善手、相手は最悪手を選ぶ。
  signが1の時は、自分は最悪手、相手は最善手を選ぶ。
*/
int precalc(int n,int sign,int st1,int st2,int last,const int m[N][N]){
  if (st1 == (1<<n)-1 && st1 == st2){
    return dp[sign][st1][st2][last] = 0;
  }
  if (last == -1){/*最初の手*/
    int ret;
    if (sign == 0)ret = -inf;
    else ret = inf;
    rep(i,n){
      int tmp = precalc(n,sign,1<<i,st2,i,m);
      if (sign == 0)ret = max(ret,-tmp);
      else if (sign == 1)ret = min(ret,-tmp);
    }
    return ret;
  }
  int &ret = dp[sign][st1][st2][last];
  if (ret != -inf)return ret;
  if (__builtin_popcount(st1) == __builtin_popcount(st2)){/*次の手は自分*/
    if (sign == 0)ret = -inf;
    else if (sign == 1)ret = inf;
    rep(i,n){
      if ((1<<i)&st1)continue;
      int tmp = precalc(n,sign,st1|(1<<i),st2,i,m);
      if (sign == 0)ret = max(ret,m[i][last] - tmp);
      else if (sign == 1)ret = min(ret,m[i][last]-tmp);
    }
  }else {
    if (sign == 0)ret = inf;
    else if (sign == 1)ret = -inf;
    rep(i,n){
      if ((1<<i)&st2)continue;
      int tmp = precalc(n,sign,st1,st2|(1<<i),i,m);
      if (sign == 0)ret = min(ret,m[last][i] - tmp);
      else if (sign == 1)ret = max(ret,m[last][i] - tmp);
    }
  }
  return ret;
}

/*
  評価値から手数を復元
*/
int getop(const int val){
  int ret = 0;
  if (val == 0){
    ret = val;
  }else if (val > 0){
    ret = val - inf;
  }else if (val < 0){
    ret = inf + val;
    ret *= -1;
  }
  return ret;
}

/*評価値から符号付き手数を復元*/
int getSignedOp(const int val){
  int ret = 0;
  if (val == 0){
    ret = val;
  }else if (val > 0){
    ret = inf - val;
  }else if (val < 0){
    ret = inf + val ;
  }
  return ret;
}

/*符号付き手数から次の符号付き手数を生成する*/
int getNextSignedOp(const int val){
  int ret = 0;
  if (val == 0){
    ret = val;
  }else if (val < 0){
    ret = val;
    ret--;
    ret *= -1;
  }else if (val > 0){
    ret = val;
    ret++;
    ret *= -1;
  }
  return ret;
}

/*
  符号付き手数から次の結果を計算する
*/
int update(const int ret,const int op){
  if (ret == -inf || ret == inf){
    return op;
  }
  if (op == 0){/*引き分け*/
    if (ret > 0)return ret;/*すでに勝つことが決まっているなら答えは変わらない*/
    else return 0;/*負けか引き分けなら引き分け*/
  }else if (op > 0){/*勝ち*/
    if (ret > 0)return min(ret,op);/*すでに勝つことが決まっているなら、最小の手数を返す*/
    else return op;/*負けか引き分けならopを返す*/
  }else if (op < 0){/*負け*/
    if (ret >= 0)return ret;/*価値か引き分けなら答えは変わらない*/
    else return min(ret,op);/*負けなら負けるまでの手数が大きい方を選ぶ*/
  }
  assert(false);
}

/*符号付き手数から評価値を返す*/
int getval(const int op){
  if (op == 0){
    return 0;
  }else if (op > 0){
    return inf - op;
  }else if (op < 0){
    return -(inf - (-op));
  }
  assert(false);
}

/*
  ALPHA-BETAカットを用いた探索を行う。
  評価値は
  勝つときはinf-手数。
  引き分けなら0
  負なら -(inf+手数)
  を評価値として使う（解説通り）

  自分の番、評価値の最大化を目指す。
  相手の番、評価値の最小化を目指す。

  自分の番、親のノードの探索途中の評価値（相手の値）よりでかいものが出てきたとする。
  　　　　　この時、自分の番で選ばれるものを、相手が選ぶことがなくなるので枝刈りできる。
            （相手は最小になる手を選ぶのでここが選ばれることがなくなるのでもう見る必要がない）
  相手の番、親の最大値（自分の値）より小さいものが出てきたら終了。
  　　　　　（自分は、最大の値となるものを選ぶ。相手は最小となるものを選ぶ。このノードから探索を続けても、相手の評価値はより小さい値にしかならず、
  　　　　　　自分の番でこのノードが選ばれることがないのがわかる。

  返り値は評価値。
  内部の計算は手数で行おう。
*/

int acut = 0,bcut = 0;
int search(int n,int st1,int st2,int last,const int m[N][N],int myp,int opp,int alpha,int beta){
  if (st1 == (1<<n)-1 && st1 == st2 ){
    if (myp > opp)return 1;
    else if (myp < opp)return -1;
    return 0;//引き分け
  }
  int ret = -inf;
  if (last == -1){
    rep(i,n){
      int tmp = search(n,(1<<i),st2,i,m,myp,opp,alpha,beta);
      int op = getNextSignedOp(tmp);
      ret = update(ret,op);
      alpha = max(alpha,getval(op));
      
    }
    return ret;
  }
  if (__builtin_popcount(st1) == __builtin_popcount(st2)){//自分の番、評価値を最大化する。
    if (myp+dp[0][st1][st2][last] < opp)return -1;//負け
    rep(i,n){
      if ((1<<i)&st1)continue;
      int tmp=search(n,st1|(1<<i),st2,i,m,myp+m[i][last],opp,alpha,beta);
      int op = getNextSignedOp(tmp);
      ret = update(ret,op);
      alpha = max(alpha,getval(tmp));
      if (alpha > beta){
	bcut++;
	break;
      }
    }
  }else {//相手の番、評価値を最小化する。
    if (myp > opp+dp[1][st1][st2][last])return -1;//負けが確定しているのでゲームを終了する
    rep(i,n){
      if ((1<<i)&st2)continue;
      int tmp=search(n,st1,st2|(1<<i),i,m,myp,opp+m[last][i],alpha,beta);
      int op = getNextSignedOp(tmp);
      ret = update(ret,op);
      beta = min(beta,getval(tmp));
      if (alpha > beta){
	acut++;
	break;
      }
    }
  }
  return ret;
}


/*
  勝ち    1
  引き分け0
  負け　　-1
*/
short dpDebug[(1<<N)][(1<<N)][(1<<N)];
short searchDebug(int n,int st1,int st2,int last,const int m[N][N],int myp,int opp,int alpha,int beta){
  if (st1 == (1<<n)-1 && st1 == st2 ){
    assert(myp == opp);
    return 0;//引き分け
  }
  if (last == -1){
    int ret = -1;
    rep(i,n){
      int tmp = searchDebug(n,(1<<i),st2,i,m,myp,opp,alpha,beta);
      if (tmp == -1)return 1;
      else if (tmp == 0)ret = 0;
    }
    return ret;
  }
  short &ret = dpDebug[st1][st2][last];
  if (ret != -2)return ret;
  ret = -1;
  if (__builtin_popcount(st1) == __builtin_popcount(st2)){//自分の番、評価値を最大化する。
    if (myp+dp[0][st1][st2][last] < opp)return -1;//負け
    rep(i,n){
    if ((1<<i)&st1)continue;
      int tmp=searchDebug(n,st1|(1<<i),st2,i,m,myp+m[i][last],opp,alpha,beta);
      if (tmp == -1)return 1;
      else if (tmp == 0)ret = 0;
    }
  }else {//相手の番、評価値を最小化する。
    if (myp > opp+dp[1][st1][st2][last])return -1;//負けが確定しているのでゲームを終了する
    rep(i,n){
      if ((1<<i)&st2)continue;
      int tmp=searchDebug(n,st1,st2|(1<<i),i,m,myp,opp+m[last][i],alpha,beta);
      if (tmp == -1)return 1;
      else if (tmp == 0)ret = 0;
    }
  }
  return ret;
}

main(){
  int n;
  int m[N][N];
  int f;
  while(cin>>n>>f && n){
    rep(i,n)rep(j,n)cin>>m[i][j];
    rep(ii,2)rep(i,(1<<n))rep(j,(1<<n))rep(k,n)dp[ii][i][j][k] = -inf;
    rep(i,(1<<n))rep(j,(1<<n))rep(k,n)dpDebug[i][j][k] = -2;
    int tmp = precalc(n,0,0,0,-1,m);
    int tmp2 = precalc(n,1,0,0,-1,m);
    if (tmp + f < 0){//特殊ケース、先手の人はどうやっても勝てない
      cout << "Second" << endl;
      cout << 1 << endl;
      continue;
    }
    
    //int ans = search(n,0,0,-1,m,f,0,-inf/2,inf/2);/*alpha,betaは後でp適切な値に修正すること。*/
    int ans   = search(     n,0,0,-1,m,f,0,-2*inf,2*inf);/*alpha,betaは後でp適切な値に修正すること。*/
    short check = searchDebug(n,0,0,-1,m,f,0,   0,  0);
    //cout <<"check " << ans <<" " << check << endl;
    if (ans == 0){
      assert(check == 0);
      cout << "Draw" << endl;
      cout << 2*n << endl;//引き分けならあきらかに2N手かかる
    }else if (ans > 0){
      assert(check == 1);
      cout << "First" << endl;
      //cout << getop(ans) << endl;
      //cout << -ans << endl;
      cout << ans << endl;
    }else if (ans < 0){
      assert(check == -1);
      cout << "Second" << endl;
      //cout << getop(ans) << endl;
      cout << -ans << endl;
    }

#ifdef DEBUG
    cout << "--------------debug" <<endl;
    cout << acut << " " << bcut << endl;
    cout << "----------------end" << endl;
#endif
  }
  return 0;
}
accuracy: 0.057692307692307696
time_ms: 70
memory_kb: 36000
final_rank: 19

code_snippet: #include<iostream>
#include<cassert>
#include<cmath>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)
const int N = 8;
const int inf = 10000000;
int dp[2][(1<<N)][(1<<N)][N];/*自分の選んだ場所、相手の選んだ場所、最後に選ばれた数字*/

/*
  最高の場合の自分と相手の点数の差を求めておく。
  探索時にこの差、で相手の点数に追いつけなければ負けが確定するので、その時点で打ち切りできるようになる。
  signが0の時は、自分は最善手、相手は最悪手を選ぶ。
  signが1の時は、自分は最悪手、相手は最善手を選ぶ。
*/
int precalc(int n,int sign,int st1,int st2,int last,const int m[N][N]){
  if (st1 == (1<<n)-1 && st1 == st2){
    return dp[sign][st1][st2][last] = 0;
  }
  if (last == -1){/*最初の手*/
    int ret;
    if (sign == 0)ret = -inf;
    else ret = inf;
    rep(i,n){
      int tmp = precalc(n,sign,1<<i,st2,i,m);
      if (sign == 0)ret = max(ret,-tmp);
      else if (sign == 1)ret = min(ret,-tmp);
    }
    return ret;
  }
  int &ret = dp[sign][st1][st2][last];
  if (ret != -inf)return ret;
  if (__builtin_popcount(st1) == __builtin_popcount(st2)){/*次の手は自分*/
    if (sign == 0)ret = -inf;
    else if (sign == 1)ret = inf;
    rep(i,n){
      if ((1<<i)&st1)continue;
      int tmp = precalc(n,sign,st1|(1<<i),st2,i,m);
      if (sign == 0)ret = max(ret,m[i][last] - tmp);
      else if (sign == 1)ret = min(ret,m[i][last]-tmp);
    }
  }else {
    if (sign == 0)ret = inf;
    else if (sign == 1)ret = -inf;
    rep(i,n){
      if ((1<<i)&st2)continue;
      int tmp = precalc(n,sign,st1,st2|(1<<i),i,m);
      if (sign == 0)ret = min(ret,m[last][i] - tmp);
      else if (sign == 1)ret = max(ret,m[last][i] - tmp);
    }
  }
  return ret;
}

/*
  評価値から手数を復元
*/
int getop(const int val){
  int ret = 0;
  if (val == 0){
    ret = val;
  }else if (val > 0){
    ret = val - inf;
  }else if (val < 0){
    ret = inf + val;
    ret *= -1;
  }
  return ret;
}

/*評価値から符号付き手数を復元*/
int getSignedOp(const int val){
  int ret = 0;
  if (val == 0){
    ret = val;
  }else if (val > 0){
    ret = inf - val;
  }else if (val < 0){
    ret = inf + val ;
  }
  return ret;
}

/*符号付き手数から次の符号付き手数を生成する*/
int getNextSignedOp(const int val){
  int ret = 0;
  if (val == 0){
    ret = val;
  }else if (val < 0){
    ret = val;
    ret--;
    ret *= -1;
  }else if (val > 0){
    ret = val;
    ret++;
    ret *= -1;
  }
  return ret;
}

/*
  符号付き手数から次の結果を計算する
*/
int update(const int ret,const int op){
  if (ret == -inf || ret == inf){
    return op;
  }
  if (op == 0){/*引き分け*/
    if (ret > 0)return ret;/*すでに勝つことが決まっているなら答えは変わらない*/
    else return 0;/*負けか引き分けなら引き分け*/
  }else if (op > 0){/*勝ち*/
    if (ret > 0)return min(ret,op);/*すでに勝つことが決まっているなら、最小の手数を返す*/
    else return op;/*負けか引き分けならopを返す*/
  }else if (op < 0){/*負け*/
    if (ret >= 0)return ret;/*価値か引き分けなら答えは変わらない*/
    else return min(ret,op);/*負けなら負けるまでの手数が大きい方を選ぶ*/
  }
  assert(false);
}

/*符号付き手数から評価値を返す*/
int getval(const int op){
  if (op == 0){
    return 0;
  }else if (op > 0){
    return inf - op;
  }else if (op < 0){
    return -(inf - (-op));
  }
  assert(false);
}

/*
  ALPHA-BETAカットを用いた探索を行う。
  評価値は
  勝つときはinf-手数。
  引き分けなら0
  負なら -(inf+手数)
  を評価値として使う（解説通り）

  自分の番、評価値の最大化を目指す。
  相手の番、評価値の最小化を目指す。

  自分の番、親のノードの探索途中の評価値（相手の値）よりでかいものが出てきたとする。
  　　　　　この時、自分の番で選ばれるものを、相手が選ぶことがなくなるので枝刈りできる。
            （相手は最小になる手を選ぶのでここが選ばれることがなくなるのでもう見る必要がない）
  相手の番、親の最大値（自分の値）より小さいものが出てきたら終了。
  　　　　　（自分は、最大の値となるものを選ぶ。相手は最小となるものを選ぶ。このノードから探索を続けても、相手の評価値はより小さい値にしかならず、
  　　　　　　自分の番でこのノードが選ばれることがないのがわかる。

  返り値は評価値。
  内部の計算は手数で行おう。
*/

int acut = 0,bcut = 0;
int search(int n,int st1,int st2,int last,const int m[N][N],int myp,int opp,int alpha,int beta){
  if (st1 == (1<<n)-1 && st1 == st2 ){
    if (myp > opp)return 1;
    else if (myp < opp)return -1;
    return 0;//引き分け
  }
  int ret = -inf;
  if (last == -1){
    rep(i,n){
      int tmp = search(n,(1<<i),st2,i,m,myp,opp,alpha,beta);
      int op = getNextSignedOp(tmp);
      ret = update(ret,op);
      alpha = max(alpha,getval(op));
      
    }
    return ret;
  }
  if (__builtin_popcount(st1) == __builtin_popcount(st2)){//自分の番、評価値を最大化する。
    if (myp+dp[0][st1][st2][last] < opp)return -1;//負け
    rep(i,n){
      if ((1<<i)&st1)continue;
      int tmp=search(n,st1|(1<<i),st2,i,m,myp+m[i][last],opp,alpha,beta);
      int op = getNextSignedOp(tmp);
      ret = update(ret,op);
      alpha = max(alpha,getval(op));
      if (alpha > beta){
	bcut++;
	break;
      }
    }
  }else {//相手の番、評価値を最小化する。
    if (myp > opp+dp[1][st1][st2][last])return -1;//負けが確定しているのでゲームを終了する
    rep(i,n){
      if ((1<<i)&st2)continue;
      int tmp=search(n,st1,st2|(1<<i),i,m,myp,opp+m[last][i],alpha,beta);
      int op = getNextSignedOp(tmp);
      ret = update(ret,op);
      beta = min(beta,getval(tmp));
      if (alpha > beta){
	acut++;
	break;
      }
    }
  }
  return ret;
}


/*
  勝ち    1
  引き分け0
  負け　　-1
*/
short dpDebug[(1<<N)][(1<<N)][(1<<N)];
short searchDebug(int n,int st1,int st2,int last,const int m[N][N],int myp,int opp,int alpha,int beta){
  if (st1 == (1<<n)-1 && st1 == st2 ){
    assert(myp == opp);
    return 0;//引き分け
  }
  if (last == -1){
    int ret = -1;
    rep(i,n){
      int tmp = searchDebug(n,(1<<i),st2,i,m,myp,opp,alpha,beta);
      if (tmp == -1)return 1;
      else if (tmp == 0)ret = 0;
    }
    return ret;
  }
  short &ret = dpDebug[st1][st2][last];
  if (ret != -2)return ret;
  ret = -1;
  if (__builtin_popcount(st1) == __builtin_popcount(st2)){//自分の番、評価値を最大化する。
    if (myp+dp[0][st1][st2][last] < opp)return -1;//負け
    rep(i,n){
    if ((1<<i)&st1)continue;
      int tmp=searchDebug(n,st1|(1<<i),st2,i,m,myp+m[i][last],opp,alpha,beta);
      if (tmp == -1)return 1;
      else if (tmp == 0)ret = 0;
    }
  }else {//相手の番、評価値を最小化する。
    if (myp > opp+dp[1][st1][st2][last])return -1;//負けが確定しているのでゲームを終了する
    rep(i,n){
      if ((1<<i)&st2)continue;
      int tmp=searchDebug(n,st1,st2|(1<<i),i,m,myp,opp+m[last][i],alpha,beta);
      if (tmp == -1)return 1;
      else if (tmp == 0)ret = 0;
    }
  }
  return ret;
}

main(){
  int n;
  int m[N][N];
  int f;
  while(cin>>n>>f && n){
    rep(i,n)rep(j,n)cin>>m[i][j];
    rep(ii,2)rep(i,(1<<n))rep(j,(1<<n))rep(k,n)dp[ii][i][j][k] = -inf;
    rep(i,(1<<n))rep(j,(1<<n))rep(k,n)dpDebug[i][j][k] = -2;
    int tmp = precalc(n,0,0,0,-1,m);
    int tmp2 = precalc(n,1,0,0,-1,m);
    if (tmp + f < 0){//特殊ケース、先手の人はどうやっても勝てない
      cout << "Second" << endl;
      cout << 1 << endl;
      continue;
    }
    
    //int ans = search(n,0,0,-1,m,f,0,-inf/2,inf/2);/*alpha,betaは後でp適切な値に修正すること。*/
    int ans   = search(     n,0,0,-1,m,f,0,-2*inf,2*inf);/*alpha,betaは後でp適切な値に修正すること。*/
    short check = searchDebug(n,0,0,-1,m,f,0,   0,  0);
    //cout <<"check " << ans <<" " << check << endl;
    if (ans == 0){
      assert(check == 0);
      cout << "Draw" << endl;
      cout << 2*n << endl;//引き分けならあきらかに2N手かかる
    }else if (ans > 0){
      assert(check == 1);
      cout << "First" << endl;
      //cout << getop(ans) << endl;
      //cout << -ans << endl;
      cout << ans << endl;
    }else if (ans < 0){
      assert(check == -1);
      cout << "Second" << endl;
      //cout << getop(ans) << endl;
      cout << -ans << endl;
    }

#ifdef DEBUG
    cout << "--------------debug" <<endl;
    cout << acut << " " << bcut << endl;
    cout << "----------------end" << endl;
#endif
  }
  return 0;
}
accuracy: 0.1346153846153846
time_ms: 130
memory_kb: 36000
final_rank: 7

code_snippet: #include<iostream>
#include<cassert>
#include<cmath>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)
const int N = 8;
const int inf = 10000000;
int dp[2][(1<<N)][(1<<N)][N];/*自分の選んだ場所、相手の選んだ場所、最後に選ばれた数字*/

/*
  最高の場合の自分と相手の点数の差を求めておく。
  探索時にこの差、で相手の点数に追いつけなければ負けが確定するので、その時点で打ち切りできるようになる。
  signが0の時は、自分は最善手、相手は最悪手を選ぶ。
  signが1の時は、自分は最悪手、相手は最善手を選ぶ。
*/
int precalc(int n,int sign,int st1,int st2,int last,const int m[N][N]){
  if (st1 == (1<<n)-1 && st1 == st2){
    return dp[sign][st1][st2][last] = 0;
  }
  if (last == -1){/*最初の手*/
    int ret;
    if (sign == 0)ret = -inf;
    else ret = inf;
    rep(i,n){
      int tmp = precalc(n,sign,1<<i,st2,i,m);
      if (sign == 0)ret = max(ret,-tmp);
      else if (sign == 1)ret = min(ret,-tmp);
    }
    return ret;
  }
  int &ret = dp[sign][st1][st2][last];
  if (ret != -inf)return ret;
  if (__builtin_popcount(st1) == __builtin_popcount(st2)){/*次の手は自分*/
    if (sign == 0)ret = -inf;
    else if (sign == 1)ret = inf;
    rep(i,n){
      if ((1<<i)&st1)continue;
      int tmp = precalc(n,sign,st1|(1<<i),st2,i,m);
      if (sign == 0)ret = max(ret,m[i][last] - tmp);
      else if (sign == 1)ret = min(ret,m[i][last]-tmp);
    }
  }else {
    if (sign == 0)ret = inf;
    else if (sign == 1)ret = -inf;
    rep(i,n){
      if ((1<<i)&st2)continue;
      int tmp = precalc(n,sign,st1,st2|(1<<i),i,m);
      if (sign == 0)ret = min(ret,m[last][i] - tmp);
      else if (sign == 1)ret = max(ret,m[last][i] - tmp);
    }
  }
  return ret;
}

/*
  評価値から手数を復元
*/
int getop(const int val){
  int ret = 0;
  if (val == 0){
    ret = val;
  }else if (val > 0){
    ret = val - inf;
  }else if (val < 0){
    ret = inf + val;
    ret *= -1;
  }
  return ret;
}

/*評価値から符号付き手数を復元*/
int getSignedOp(const int val){
  int ret = 0;
  if (val == 0){
    ret = val;
  }else if (val > 0){
    ret = inf - val;
  }else if (val < 0){
    ret = inf + val ;
  }
  return ret;
}

/*符号付き手数から次の符号付き手数を生成する*/
int getNextSignedOp(const int val){
  int ret = 0;
  if (val == 0){
    ret = val;
  }else if (val < 0){
    ret = val;
    ret--;
    ret *= -1;
  }else if (val > 0){
    ret = val;
    ret++;
    ret *= -1;
  }
  return ret;
}

/*
  符号付き手数から次の結果を計算する
*/
int update(const int ret,const int op){
  if (ret == -inf || ret == inf){
    return op;
  }
  if (op == 0){/*引き分け*/
    if (ret > 0)return ret;/*すでに勝つことが決まっているなら答えは変わらない*/
    else return 0;/*負けか引き分けなら引き分け*/
  }else if (op > 0){/*勝ち*/
    if (ret > 0)return min(ret,op);/*すでに勝つことが決まっているなら、最小の手数を返す*/
    else return op;/*負けか引き分けならopを返す*/
  }else if (op < 0){/*負け*/
    if (ret >= 0)return ret;/*価値か引き分けなら答えは変わらない*/
    else return min(ret,op);/*負けなら負けるまでの手数が大きい方を選ぶ*/
  }
  assert(false);
}

/*符号付き手数から評価値を返す*/
int getval(const int op){
  if (op == 0){
    return 0;
  }else if (op > 0){
    return inf - op;
  }else if (op < 0){
    return -(inf - (-op));
  }
  assert(false);
}

/*
  ALPHA-BETAカットを用いた探索を行う。
  評価値は
  勝つときはinf-手数。
  引き分けなら0
  負なら -(inf+手数)
  を評価値として使う（解説通り）

  自分の番、評価値の最大化を目指す。
  相手の番、評価値の最小化を目指す。

  自分の番、親のノードの探索途中の評価値（相手の値）よりでかいものが出てきたとする。
  　　　　　この時、自分の番で選ばれるものを、相手が選ぶことがなくなるので枝刈りできる。
            （相手は最小になる手を選ぶのでここが選ばれることがなくなるのでもう見る必要がない）
  相手の番、親の最大値（自分の値）より小さいものが出てきたら終了。
  　　　　　（自分は、最大の値となるものを選ぶ。相手は最小となるものを選ぶ。このノードから探索を続けても、相手の評価値はより小さい値にしかならず、
  　　　　　　自分の番でこのノードが選ばれることがないのがわかる。

  返り値は評価値。
  内部の計算は手数で行おう。
*/

int acut = 0,bcut = 0;
int search(int n,int st1,int st2,int last,const int m[N][N],int myp,int opp,int alpha,int beta){
  if (st1 == (1<<n)-1 && st1 == st2 ){
    if (myp > opp)return 1;
    else if (myp < opp)return -1;
    return 0;//引き分け
  }
  int ret = -inf;
  if (last == -1){
    rep(i,n){
      int tmp = search(n,(1<<i),st2,i,m,myp,opp,alpha,beta);
      int op = getNextSignedOp(tmp);
      ret = update(ret,op);
      alpha = max(alpha,getval(op));
      
    }
    return ret;
  }
  if (__builtin_popcount(st1) == __builtin_popcount(st2)){//自分の番、評価値を最大化する。
    if (myp+dp[0][st1][st2][last] < opp)return -1;//負け
    rep(i,n){
      if ((1<<i)&st1)continue;
      int tmp=search(n,st1|(1<<i),st2,i,m,myp+m[i][last],opp,alpha,beta);
      int op = getNextSignedOp(tmp);
      ret = update(ret,op);
      alpha = max(alpha,getval(op));
      if (alpha < beta){
	bcut++;
	break;
      }
    }
  }else {//相手の番、評価値を最小化する。
    if (myp > opp+dp[1][st1][st2][last])return -1;//負けが確定しているのでゲームを終了する
    rep(i,n){
      if ((1<<i)&st2)continue;
      int tmp=search(n,st1,st2|(1<<i),i,m,myp,opp+m[last][i],alpha,beta);
      int op = getNextSignedOp(tmp);
      ret = update(ret,op);
      beta = min(beta,getval(tmp));
      if (alpha > beta){
	acut++;
	break;
      }
    }
  }
  return ret;
}


/*
  勝ち    1
  引き分け0
  負け　　-1
*/
short dpDebug[(1<<N)][(1<<N)][(1<<N)];
short searchDebug(int n,int st1,int st2,int last,const int m[N][N],int myp,int opp,int alpha,int beta){
  if (st1 == (1<<n)-1 && st1 == st2 ){
    assert(myp == opp);
    return 0;//引き分け
  }
  if (last == -1){
    int ret = -1;
    rep(i,n){
      int tmp = searchDebug(n,(1<<i),st2,i,m,myp,opp,alpha,beta);
      if (tmp == -1)return 1;
      else if (tmp == 0)ret = 0;
    }
    return ret;
  }
  short &ret = dpDebug[st1][st2][last];
  if (ret != -2)return ret;
  ret = -1;
  if (__builtin_popcount(st1) == __builtin_popcount(st2)){//自分の番、評価値を最大化する。
    if (myp+dp[0][st1][st2][last] < opp)return -1;//負け
    rep(i,n){
    if ((1<<i)&st1)continue;
      int tmp=searchDebug(n,st1|(1<<i),st2,i,m,myp+m[i][last],opp,alpha,beta);
      if (tmp == -1)return 1;
      else if (tmp == 0)ret = 0;
    }
  }else {//相手の番、評価値を最小化する。
    if (myp > opp+dp[1][st1][st2][last])return -1;//負けが確定しているのでゲームを終了する
    rep(i,n){
      if ((1<<i)&st2)continue;
      int tmp=searchDebug(n,st1,st2|(1<<i),i,m,myp,opp+m[last][i],alpha,beta);
      if (tmp == -1)return 1;
      else if (tmp == 0)ret = 0;
    }
  }
  return ret;
}

main(){
  int n;
  int m[N][N];
  int f;
  while(cin>>n>>f && n){
    rep(i,n)rep(j,n)cin>>m[i][j];
    rep(ii,2)rep(i,(1<<n))rep(j,(1<<n))rep(k,n)dp[ii][i][j][k] = -inf;
    rep(i,(1<<n))rep(j,(1<<n))rep(k,n)dpDebug[i][j][k] = -2;
    int tmp = precalc(n,0,0,0,-1,m);
    int tmp2 = precalc(n,1,0,0,-1,m);
    if (tmp + f < 0){//特殊ケース、先手の人はどうやっても勝てない
      cout << "Second" << endl;
      cout << 1 << endl;
      continue;
    }
    
    //int ans = search(n,0,0,-1,m,f,0,-inf/2,inf/2);/*alpha,betaは後でp適切な値に修正すること。*/
    int ans   = search(     n,0,0,-1,m,f,0,-2*inf,2*inf);/*alpha,betaは後でp適切な値に修正すること。*/
    short check = searchDebug(n,0,0,-1,m,f,0,   0,  0);
    //cout <<"check " << ans <<" " << check << endl;
    if (ans == 0){
      assert(check == 0);
      cout << "Draw" << endl;
      cout << 2*n << endl;//引き分けならあきらかに2N手かかる
    }else if (ans > 0){
      assert(check == 1);
      cout << "First" << endl;
      //cout << getop(ans) << endl;
      //cout << -ans << endl;
      cout << ans << endl;
    }else if (ans < 0){
      assert(check == -1);
      cout << "Second" << endl;
      //cout << getop(ans) << endl;
      cout << -ans << endl;
    }

    /*
    cout << "--------------debug" <<endl;
    cout << acut << " " << bcut << endl;
    cout << "----------------end" << endl;
    */
  }
  return 0;
}
accuracy: 0.1346153846153846
time_ms: 140
memory_kb: 0
final_rank: 4

code_snippet: #include<iostream>
#include<cassert>
#include<cmath>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)
const int N = 8;
const int inf = 10000000;
int dp[2][(1<<N)][(1<<N)][N];/*自分の選んだ場所、相手の選んだ場所、最後に選ばれた数字*/

/*
  最高の場合の自分と相手の点数の差を求めておく。
  探索時にこの差、で相手の点数に追いつけなければ負けが確定するので、その時点で打ち切りできるようになる。
  signが0の時は、自分は最善手、相手は最悪手を選ぶ。
  signが1の時は、自分は最悪手、相手は最善手を選ぶ。
*/
int precalc(int n,int sign,int st1,int st2,int last,const int m[N][N]){
  if (st1 == (1<<n)-1 && st1 == st2){
    return dp[sign][st1][st2][last] = 0;
  }
  if (last == -1){/*最初の手*/
    int ret;
    if (sign == 0)ret = -inf;
    else ret = inf;
    rep(i,n){
      int tmp = precalc(n,sign,1<<i,st2,i,m);
      if (sign == 0)ret = max(ret,-tmp);
      else if (sign == 1)ret = min(ret,-tmp);
    }
    return ret;
  }
  int &ret = dp[sign][st1][st2][last];
  if (ret != -inf)return ret;
  if (__builtin_popcount(st1) == __builtin_popcount(st2)){/*次の手は自分*/
    if (sign == 0)ret = -inf;
    else if (sign == 1)ret = inf;
    rep(i,n){
      if ((1<<i)&st1)continue;
      int tmp = precalc(n,sign,st1|(1<<i),st2,i,m);
      if (sign == 0)ret = max(ret,m[i][last] - tmp);
      else if (sign == 1)ret = min(ret,m[i][last]-tmp);
    }
  }else {
    if (sign == 0)ret = inf;
    else if (sign == 1)ret = -inf;
    rep(i,n){
      if ((1<<i)&st2)continue;
      int tmp = precalc(n,sign,st1,st2|(1<<i),i,m);
      if (sign == 0)ret = min(ret,m[last][i] - tmp);
      else if (sign == 1)ret = max(ret,m[last][i] - tmp);
    }
  }
  return ret;
}

/*
  評価値から手数を復元
*/
int getop(const int val){
  int ret = 0;
  if (val == 0){
    ret = val;
  }else if (val > 0){
    ret = val - inf;
  }else if (val < 0){
    ret = inf + val;
    ret *= -1;
  }
  return ret;
}

/*評価値から符号付き手数を復元*/
int getSignedOp(const int val){
  int ret = 0;
  if (val == 0){
    ret = val;
  }else if (val > 0){
    ret = inf - val;
  }else if (val < 0){
    ret = inf + val ;
  }
  return ret;
}

/*符号付き手数から次の符号付き手数を生成する*/
int getNextSignedOp(const int val){
  int ret = 0;
  if (val == 0){
    ret = val;
  }else if (val < 0){
    ret = val;
    ret--;
    ret *= -1;
  }else if (val > 0){
    ret = val;
    ret++;
    ret *= -1;
  }
  return ret;
}

/*
  符号付き手数から次の結果を計算する
*/
int update(const int ret,const int op){
  if (ret == -inf || ret == inf){
    return op;
  }
  if (op == 0){/*引き分け*/
    if (ret > 0)return ret;/*すでに勝つことが決まっているなら答えは変わらない*/
    else return 0;/*負けか引き分けなら引き分け*/
  }else if (op > 0){/*勝ち*/
    if (ret > 0)return min(ret,op);/*すでに勝つことが決まっているなら、最小の手数を返す*/
    else return op;/*負けか引き分けならopを返す*/
  }else if (op < 0){/*負け*/
    if (ret >= 0)return ret;/*価値か引き分けなら答えは変わらない*/
    else return min(ret,op);/*負けなら負けるまでの手数が大きい方を選ぶ*/
  }
  assert(false);
}

/*符号付き手数から評価値を返す*/
int getval(const int op){
  if (op == 0){
    return 0;
  }else if (op > 0){
    return inf - op;
  }else if (op < 0){
    return -(inf - (-op));
  }
  assert(false);
}

/*
  ALPHA-BETAカットを用いた探索を行う。
  評価値は
  勝つときはinf-手数。
  引き分けなら0
  負なら -(inf+手数)
  を評価値として使う（解説通り）

  自分の番、評価値の最大化を目指す。
  相手の番、評価値の最小化を目指す。

  自分の番、親のノードの探索途中の評価値（相手の値）よりでかいものが出てきたとする。
  　　　　　この時、自分の番で選ばれるものを、相手が選ぶことがなくなるので枝刈りできる。
            （相手は最小になる手を選ぶのでここが選ばれることがなくなるのでもう見る必要がない）
  相手の番、親の最大値（自分の値）より小さいものが出てきたら終了。
  　　　　　（自分は、最大の値となるものを選ぶ。相手は最小となるものを選ぶ。このノードから探索を続けても、相手の評価値はより小さい値にしかならず、
  　　　　　　自分の番でこのノードが選ばれることがないのがわかる。

  返り値は評価値。
  内部の計算は手数で行おう。
*/

int acut = 0,bcut = 0;
int search(int n,int st1,int st2,int last,const int m[N][N],int myp,int opp,int alpha,int beta){
  if (st1 == (1<<n)-1 && st1 == st2 ){
    if (myp > opp)return 1;
    else if (myp < opp)return -1;
    return 0;//引き分け
  }
  int ret = -inf;
  if (last == -1){
    rep(i,n){
      int tmp = search(n,(1<<i),st2,i,m,myp,opp,alpha,beta);
      int op = getNextSignedOp(tmp);
      ret = update(ret,op);
      alpha = max(alpha,tmp);
    }
    return ret;
  }
  if (__builtin_popcount(st1) == __builtin_popcount(st2)){//自分の番、評価値を最大化する。
    if (myp+dp[0][st1][st2][last] < opp)return -1;//負け
    rep(i,n){
      if ((1<<i)&st1)continue;
      int tmp=search(n,st1|(1<<i),st2,i,m,myp+m[i][last],opp,alpha,beta);
      int op = getNextSignedOp(tmp);
      ret = update(ret,op);
      
      alpha = max(alpha,tmp);
      if (alpha > beta){
	bcut++;
	break;
      }
    }
  }else {//相手の番、評価値を最小化する。
    if (myp > opp+dp[1][st1][st2][last])return -1;//負けが確定しているのでゲームを終了する
    rep(i,n){
      if ((1<<i)&st2)continue;
      int tmp=search(n,st1,st2|(1<<i),i,m,myp,opp+m[last][i],alpha,beta);
      int op = getNextSignedOp(tmp);
      ret = update(ret,op);
      beta = min(beta,tmp);
      if (alpha < beta){
	acut++;
	//break;
      }
    }
  }
  return ret;
}


/*
  勝ち    1
  引き分け0
  負け　　-1
*/
short dpDebug[(1<<N)][(1<<N)][(1<<N)];
short searchDebug(int n,int st1,int st2,int last,const int m[N][N],int myp,int opp,int alpha,int beta){
  if (st1 == (1<<n)-1 && st1 == st2 ){
    assert(myp == opp);
    return 0;//引き分け
  }
  if (last == -1){
    int ret = -1;
    rep(i,n){
      int tmp = searchDebug(n,(1<<i),st2,i,m,myp,opp,alpha,beta);
      if (tmp == -1)return 1;
      else if (tmp == 0)ret = 0;
    }
    return ret;
  }
  short &ret = dpDebug[st1][st2][last];
  if (ret != -2)return ret;
  ret = -1;
  if (__builtin_popcount(st1) == __builtin_popcount(st2)){//自分の番、評価値を最大化する。
    if (myp+dp[0][st1][st2][last] < opp)return -1;//負け
    rep(i,n){
    if ((1<<i)&st1)continue;
      int tmp=searchDebug(n,st1|(1<<i),st2,i,m,myp+m[i][last],opp,alpha,beta);
      if (tmp == -1)return 1;
      else if (tmp == 0)ret = 0;
    }
  }else {//相手の番、評価値を最小化する。
    if (myp > opp+dp[1][st1][st2][last])return -1;//負けが確定しているのでゲームを終了する
    rep(i,n){
      if ((1<<i)&st2)continue;
      int tmp=searchDebug(n,st1,st2|(1<<i),i,m,myp,opp+m[last][i],alpha,beta);
      if (tmp == -1)return 1;
      else if (tmp == 0)ret = 0;
    }
  }
  return ret;
}

main(){
  int n;
  int m[N][N];
  int f;
  while(cin>>n>>f && n){
    rep(i,n)rep(j,n)cin>>m[i][j];
    rep(ii,2)rep(i,(1<<n))rep(j,(1<<n))rep(k,n)dp[ii][i][j][k] = -inf;
    rep(i,(1<<n))rep(j,(1<<n))rep(k,n)dpDebug[i][j][k] = -2;
    int tmp = precalc(n,0,0,0,-1,m);
    int tmp2 = precalc(n,1,0,0,-1,m);
    if (tmp + f < 0){//特殊ケース、先手の人はどうやっても勝てない
      cout << "Second" << endl;
      cout << 1 << endl;
      continue;
    }
    
    //int ans = search(n,0,0,-1,m,f,0,-inf/2,inf/2);/*alpha,betaは後でp適切な値に修正すること。*/
    int ans   = search(     n,0,0,-1,m,f,0,-2*inf,2*inf);/*alpha,betaは後でp適切な値に修正すること。*/
    short check = searchDebug(n,0,0,-1,m,f,0,   0,  0);
    //cout <<"check " << ans <<" " << check << endl;
    if (ans == 0){
      assert(check == 0);
      cout << "Draw" << endl;
      cout << 2*n << endl;//引き分けならあきらかに2N手かかる
    }else if (ans > 0){
      assert(check == 1);
      cout << "First" << endl;
      //cout << getop(ans) << endl;
      //cout << -ans << endl;
      cout << ans << endl;
    }else if (ans < 0){
      assert(check == -1);
      cout << "Second" << endl;
      //cout << getop(ans) << endl;
      cout << -ans << endl;
    }

    /*
    cout << "--------------debug" <<endl;
    cout << acut << " " << bcut << endl;
    cout << "----------------end" << endl;
    */
  }
  return 0;
}
accuracy: 0.057692307692307696
time_ms: 110
memory_kb: 36000
final_rank: 20

code_snippet: #include<iostream>
#include<cassert>
#include<cmath>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)
const int N = 8;
const int inf = 10000000;
int dp[2][(1<<N)][(1<<N)][N];/*自分の選んだ場所、相手の選んだ場所、最後に選ばれた数字*/

/*
  最高の場合の自分と相手の点数の差を求めておく。
  探索時にこの差、で相手の点数に追いつけなければ負けが確定するので、その時点で打ち切りできるようになる。
  signが0の時は、自分は最善手、相手は最悪手を選ぶ。
  signが1の時は、自分は最悪手、相手は最善手を選ぶ。
*/
int precalc(int n,int sign,int st1,int st2,int last,const int m[N][N]){
  if (st1 == (1<<n)-1 && st1 == st2){
    return dp[sign][st1][st2][last] = 0;
  }
  if (last == -1){/*最初の手*/
    int ret;
    if (sign == 0)ret = -inf;
    else ret = inf;
    rep(i,n){
      int tmp = precalc(n,sign,1<<i,st2,i,m);
      if (sign == 0)ret = max(ret,-tmp);
      else if (sign == 1)ret = min(ret,-tmp);
    }
    return ret;
  }
  int &ret = dp[sign][st1][st2][last];
  if (ret != -inf)return ret;
  if (__builtin_popcount(st1) == __builtin_popcount(st2)){/*次の手は自分*/
    if (sign == 0)ret = -inf;
    else if (sign == 1)ret = inf;
    rep(i,n){
      if ((1<<i)&st1)continue;
      int tmp = precalc(n,sign,st1|(1<<i),st2,i,m);
      if (sign == 0)ret = max(ret,m[i][last] - tmp);
      else if (sign == 1)ret = min(ret,m[i][last]-tmp);
    }
  }else {
    if (sign == 0)ret = inf;
    else if (sign == 1)ret = -inf;
    rep(i,n){
      if ((1<<i)&st2)continue;
      int tmp = precalc(n,sign,st1,st2|(1<<i),i,m);
      if (sign == 0)ret = min(ret,m[last][i] - tmp);
      else if (sign == 1)ret = max(ret,m[last][i] - tmp);
    }
  }
  return ret;
}

/*
  評価値から手数を復元
*/
int getop(const int val){
  int ret = 0;
  if (val == 0){
    ret = val;
  }else if (val > 0){
    ret = val - inf;
  }else if (val < 0){
    ret = inf + val;
    ret *= -1;
  }
  return ret;
}

/*評価値から符号付き手数を復元*/
int getSignedOp(const int val){
  int ret = 0;
  if (val == 0){
    ret = val;
  }else if (val > 0){
    ret = inf - val;
  }else if (val < 0){
    ret = inf + val ;
  }
  return ret;
}

/*符号付き手数から次の符号付き手数を生成する*/
int getNextSignedOp(const int val){
  int ret = 0;
  if (val == 0){
    ret = val;
  }else if (val < 0){
    ret = val;
    ret--;
    ret *= -1;
  }else if (val > 0){
    ret = val;
    ret++;
    ret *= -1;
  }
  return ret;
}

/*
  符号付き手数から次の結果を計算する
*/
int update(const int ret,const int op){
  if (ret == -inf || ret == inf){
    return op;
  }
  if (op == 0){/*引き分け*/
    if (ret > 0)return ret;/*すでに勝つことが決まっているなら答えは変わらない*/
    else return 0;/*負けか引き分けなら引き分け*/
  }else if (op > 0){/*勝ち*/
    if (ret > 0)return min(ret,op);/*すでに勝つことが決まっているなら、最小の手数を返す*/
    else return op;/*負けか引き分けならopを返す*/
  }else if (op < 0){/*負け*/
    if (ret >= 0)return ret;/*価値か引き分けなら答えは変わらない*/
    else return min(ret,op);/*負けなら負けるまでの手数が大きい方を選ぶ*/
  }
  assert(false);
}

/*符号付き手数から評価値を返す*/
int getval(const int op){
  if (op == 0){
    return 0;
  }else if (op > 0){
    return inf - op;
  }else if (op < 0){
    return -(inf + -op);
  }
  assert(false);
}

/*
  ALPHA-BETAカットを用いた探索を行う。
  評価値は
  勝つときはinf-手数。
  引き分けなら0
  負なら -(inf+手数)
  を評価値として使う（解説通り）

  自分の番、評価値の最大化を目指す。
  相手の番、評価値の最小化を目指す。

  自分の番、親のノードの探索途中の評価値（相手の値）よりでかいものが出てきたとする。
  　　　　　この時、自分の番で選ばれるものを、相手が選ぶことがなくなるので枝刈りできる。
            （相手は最小になる手を選ぶのでここが選ばれることがなくなるのでもう見る必要がない）
  相手の番、親の最大値（自分の値）より小さいものが出てきたら終了。
  　　　　　（自分は、最大の値となるものを選ぶ。相手は最小となるものを選ぶ。このノードから探索を続けても、相手の評価値はより小さい値にしかならず、
  　　　　　　自分の番でこのノードが選ばれることがないのがわかる。

  返り値は評価値。
  内部の計算は手数で行おう。
*/

int acut = 0,bcut = 0;
int search(int n,int st1,int st2,int last,const int m[N][N],int myp,int opp,int alpha,int beta){
  if (st1 == (1<<n)-1 && st1 == st2 ){
    if (myp > opp)return 1;
    else if (myp < opp)return -1;
    return 0;//引き分け
  }
  int ret = -inf;
  if (last == -1){
    rep(i,n){
      int tmp = search(n,(1<<i),st2,i,m,myp,opp,alpha,beta);
      int op = getNextSignedOp(tmp);
      ret = update(ret,op);
      alpha = max(alpha,getval(ret));
    }
    return ret;
  }
  if (__builtin_popcount(st1) == __builtin_popcount(st2)){//自分の番、評価値を最大化する。
    if (myp+dp[0][st1][st2][last] < opp)return -1;//負け
    rep(i,n){
      if ((1<<i)&st1)continue;
      int tmp=search(n,st1|(1<<i),st2,i,m,myp+m[i][last],opp,alpha,beta);
      int op = getNextSignedOp(tmp);
      ret = update(ret,op);
      
      alpha = max(alpha,getval(ret));
      if (alpha <= beta){
	bcut++;
	break;
      }
    }
  }else {//相手の番、評価値を最小化する。
    if (myp > opp+dp[1][st1][st2][last])return -1;//負けが確定しているのでゲームを終了する
    rep(i,n){
      if ((1<<i)&st2)continue;
      int tmp=search(n,st1,st2|(1<<i),i,m,myp,opp+m[last][i],alpha,beta);
      int op = getNextSignedOp(tmp);
      ret = update(ret,op);
      beta = min(beta,getval(ret));
      if (alpha <= beta){
	acut++;
	break;
      }
    }
  }
  return ret;
}


/*
  勝ち    1
  引き分け0
  負け　　-1
*/
short dpDebug[(1<<N)][(1<<N)][(1<<N)];
short searchDebug(int n,int st1,int st2,int last,const int m[N][N],int myp,int opp,int alpha,int beta){
  if (st1 == (1<<n)-1 && st1 == st2 ){
    assert(myp == opp);
    return 0;//引き分け
  }
  if (last == -1){
    int ret = -1;
    rep(i,n){
      int tmp = searchDebug(n,(1<<i),st2,i,m,myp,opp,alpha,beta);
      if (tmp == -1)return 1;
      else if (tmp == 0)ret = 0;
    }
    return ret;
  }
  short &ret = dpDebug[st1][st2][last];
  if (ret != -2)return ret;
  ret = -1;
  if (__builtin_popcount(st1) == __builtin_popcount(st2)){//自分の番、評価値を最大化する。
    if (myp+dp[0][st1][st2][last] < opp)return -1;//負け
    rep(i,n){
    if ((1<<i)&st1)continue;
      int tmp=searchDebug(n,st1|(1<<i),st2,i,m,myp+m[i][last],opp,alpha,beta);
      if (tmp == -1)return 1;
      else if (tmp == 0)ret = 0;
    }
  }else {//相手の番、評価値を最小化する。
    if (myp > opp+dp[1][st1][st2][last])return -1;//負けが確定しているのでゲームを終了する
    rep(i,n){
      if ((1<<i)&st2)continue;
      int tmp=searchDebug(n,st1,st2|(1<<i),i,m,myp,opp+m[last][i],alpha,beta);
      if (tmp == -1)return 1;
      else if (tmp == 0)ret = 0;
    }
  }
  return ret;
}

main(){
  int n;
  int m[N][N];
  int f;
  while(cin>>n>>f && n){
    rep(i,n)rep(j,n)cin>>m[i][j];
    rep(ii,2)rep(i,(1<<n))rep(j,(1<<n))rep(k,n)dp[ii][i][j][k] = -inf;
    rep(i,(1<<n))rep(j,(1<<n))rep(k,n)dpDebug[i][j][k] = -2;
    int tmp = precalc(n,0,0,0,-1,m);
    int tmp2 = precalc(n,1,0,0,-1,m);
    if (tmp + f < 0){//特殊ケース、先手の人はどうやっても勝てない
      cout << "Second" << endl;
      cout << 1 << endl;
      continue;
    }
    
    //int ans = search(n,0,0,-1,m,f,0,-inf/2,inf/2);/*alpha,betaは後でp適切な値に修正すること。*/
    int ans   = search(     n,0,0,-1,m,f,0,-inf,inf);/*alpha,betaは後でp適切な値に修正すること。*/
    short check = searchDebug(n,0,0,-1,m,f,0,   0,  0);
    //cout <<"check " << ans <<" " << check << endl;
    if (ans == 0){
      assert(check == 0);
      cout << "Draw" << endl;
      cout << 2*n << endl;//引き分けならあきらかに2N手かかる
    }else if (ans > 0){
      assert(check == 1);
      cout << "First" << endl;
      //cout << getop(ans) << endl;
      //cout << -ans << endl;
      cout << ans << endl;
    }else if (ans < 0){
      assert(check == -1);
      cout << "Second" << endl;
      //cout << getop(ans) << endl;
      cout << -ans << endl;
    }

    /*
    cout << "--------------debug" <<endl;
    cout << acut << " " << bcut << endl;
    cout << "----------------end" << endl;
    */
  }
  return 0;
}
accuracy: 0.11538461538461539
time_ms: 40
memory_kb: 36000
final_rank: 11

code_snippet: #include<iostream>
#include<cassert>
#include<cmath>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)
const int N = 8;
const int inf = 10000000;
int dp[2][(1<<N)][(1<<N)][N];/*自分の選んだ場所、相手の選んだ場所、最後に選ばれた数字*/

/*
  最高の場合の自分と相手の点数の差を求めておく。
  探索時にこの差、で相手の点数に追いつけなければ負けが確定するので、その時点で打ち切りできるようになる。
  signが0の時は、自分は最善手、相手は最悪手を選ぶ。
  signが1の時は、自分は最悪手、相手は最善手を選ぶ。
*/
int precalc(int n,int sign,int st1,int st2,int last,const int m[N][N]){
  if (st1 == (1<<n)-1 && st1 == st2){
    return dp[sign][st1][st2][last] = 0;
  }
  if (last == -1){/*最初の手*/
    int ret;
    if (sign == 0)ret = -inf;
    else ret = inf;
    rep(i,n){
      int tmp = precalc(n,sign,1<<i,st2,i,m);
      if (sign == 0)ret = max(ret,-tmp);
      else if (sign == 1)ret = min(ret,-tmp);
    }
    return ret;
  }
  int &ret = dp[sign][st1][st2][last];
  if (ret != -inf)return ret;
  if (__builtin_popcount(st1) == __builtin_popcount(st2)){/*次の手は自分*/
    if (sign == 0)ret = -inf;
    else if (sign == 1)ret = inf;
    rep(i,n){
      if ((1<<i)&st1)continue;
      int tmp = precalc(n,sign,st1|(1<<i),st2,i,m);
      if (sign == 0)ret = max(ret,m[i][last] - tmp);
      else if (sign == 1)ret = min(ret,m[i][last]-tmp);
    }
  }else {
    if (sign == 0)ret = inf;
    else if (sign == 1)ret = -inf;
    rep(i,n){
      if ((1<<i)&st2)continue;
      int tmp = precalc(n,sign,st1,st2|(1<<i),i,m);
      if (sign == 0)ret = min(ret,m[last][i] - tmp);
      else if (sign == 1)ret = max(ret,m[last][i] - tmp);
    }
  }
  return ret;
}

/*
  評価値から手数を復元
*/
int getop(const int val){
  int ret = 0;
  if (val == 0){
    ret = val;
  }else if (val > 0){
    ret = val - inf;
  }else if (val < 0){
    ret = inf + val;
    ret *= -1;
  }
  return ret;
}

/*評価値から符号付き手数を復元*/
int getSignedOp(const int val){
  int ret = 0;
  if (val == 0){
    ret = val;
  }else if (val > 0){
    ret = inf - val;
  }else if (val < 0){
    ret = inf + val ;
  }
  return ret;
}

/*符号付き手数から次の符号付き手数を生成する*/
int getNextSignedOp(const int val){
  int ret = 0;
  if (val == 0){
    ret = val;
  }else if (val < 0){
    ret = val;
    ret--;
    ret *= -1;
  }else if (val > 0){
    ret = val;
    ret++;
    ret *= -1;
  }
  return ret;
}

/*
  符号付き手数から次の結果を計算する
*/
int update(const int ret,const int op){
  if (ret == -inf || ret == inf){
    return op;
  }
  if (op == 0){/*引き分け*/
    if (ret > 0)return ret;/*すでに勝つことが決まっているなら答えは変わらない*/
    else return 0;/*負けか引き分けなら引き分け*/
  }else if (op > 0){/*勝ち*/
    if (ret > 0)return min(ret,op);/*すでに勝つことが決まっているなら、最小の手数を返す*/
    else return op;/*負けか引き分けならopを返す*/
  }else if (op < 0){/*負け*/
    if (ret >= 0)return ret;/*価値か引き分けなら答えは変わらない*/
    else return min(ret,op);/*負けなら負けるまでの手数が大きい方を選ぶ*/
  }
  assert(false);
}

/*符号付き手数から評価値を返す*/
int getval(const int op){
  if (op == 0){
    return 0;
  }else if (op > 0){
    return inf - op;
  }else if (op < 0){
    return -(inf + -op);
  }
  assert(false);
}

/*
  ALPHA-BETAカットを用いた探索を行う。
  評価値は
  勝つときはinf-手数。
  引き分けなら0
  負なら -(inf+手数)
  を評価値として使う（解説通り）

  自分の番、評価値の最大化を目指す。
  相手の番、評価値の最小化を目指す。

  自分の番、親のノードの探索途中の評価値（相手の値）よりでかいものが出てきたとする。
  　　　　　この時、自分の番で選ばれるものを、相手が選ぶことがなくなるので枝刈りできる。
            （相手は最小になる手を選ぶのでここが選ばれることがなくなるのでもう見る必要がない）
  相手の番、親の最大値（自分の値）より小さいものが出てきたら終了。
  　　　　　（自分は、最大の値となるものを選ぶ。相手は最小となるものを選ぶ。このノードから探索を続けても、相手の評価値はより小さい値にしかならず、
  　　　　　　自分の番でこのノードが選ばれることがないのがわかる。

  返り値は評価値。
  内部の計算は手数で行おう。
*/

int acut = 0,bcut = 0;
/*
int search(int n,int st1,int st2,int last,const int m[N][N],int myp,int opp,int alpha,int beta){
  if (st1 == (1<<n)-1 && st1 == st2 ){
    return 0;//引き分け
  }
  int ret;
  if (last == -1){
    ret = -inf;
    rep(i,n){
      int tmp = search(n,(1<<i),st2,i,m,myp,opp,alpha,beta);
      int op = tmp;
      ret = max(ret,op);
    }
    return ret;
  }
  if (__builtin_popcount(st1) == __builtin_popcount(st2)){//自分の番、評価値を最大化する。
    if (myp+dp[0][st1][st2][last] < opp)return -(inf+1);//負け
    ret = -inf;
    rep(i,n){
      if ((1<<i)&st1)continue;
      int tmp=search(n,st1|(1<<i),st2,i,m,myp+m[i][last],opp,alpha,beta);
      int op = tmp;
      ret = max(ret,op);
    }
  }else {//相手の番、評価値を最小化する。
    if (myp > opp+dp[1][st1][st2][last])return -(inf+1);//負けが確定しているのでゲームを終了する
    ret = inf;
    rep(i,n){
      if ((1<<i)&st2)continue;
      int tmp=search(n,st1,st2|(1<<i),i,m,myp,opp+m[last][i],alpha,beta);
      int op = tmp;
      ret = min(ret,op);
    }
  }
  return getval(getNextSignedOp(getSignedOp(ret)));
}
*/

int search(int n,int st1,int st2,int last,const int m[N][N],int myp,int opp,int alpha,int beta){
  if (st1 == (1<<n)-1 && st1 == st2 ){
    if (myp > opp)return 1;
    else if (myp < opp)return -1;
    return 0;//引き分け
  }
  int ret = -inf;
  if (last == -1){
    rep(i,n){
      int tmp = search(n,(1<<i),st2,i,m,myp,opp,alpha,beta);
      int op = getNextSignedOp(tmp);
      ret = update(ret,op);
    }
    return ret;
  }
  if (__builtin_popcount(st1) == __builtin_popcount(st2)){//自分の番、評価値を最大化する。
    if (myp+dp[0][st1][st2][last] < opp)return -1;//負け
    rep(i,n){
      if ((1<<i)&st1)continue;
      int tmp=search(n,st1|(1<<i),st2,i,m,myp+m[i][last],opp,alpha,beta);
      int op = getNextSignedOp(tmp);
      ret = update(ret,op);
      
      alpha = max(alpha,getval(ret));
      if (alpha < beta){
	bcut++;
	break;
      }
    }
  }else {//相手の番、評価値を最小化する。
    if (myp > opp+dp[1][st1][st2][last])return -1;//負けが確定しているのでゲームを終了する
    rep(i,n){
      if ((1<<i)&st2)continue;
      int tmp=search(n,st1,st2|(1<<i),i,m,myp,opp+m[last][i],alpha,beta);
      int op = getNextSignedOp(tmp);
      ret = update(ret,op);
      beta = min(beta,getval(ret));
      if (alpha < beta){
	acut++;
	break;
      }
    }
  }
  return ret;
}


/*
  勝ち    1
  引き分け0
  負け　　-1
*/
int dpDebug[(1<<N)][(1<<N)][(1<<N)];
int searchDebug(int n,int st1,int st2,int last,const int m[N][N],int myp,int opp,int alpha,int beta){
  if (st1 == (1<<n)-1 && st1 == st2 ){
    assert(myp == opp);
    return 0;//引き分け
  }
  if (last == -1){
    int ret = -1;
    rep(i,n){
      int tmp = searchDebug(n,(1<<i),st2,i,m,myp,opp,alpha,beta);
      if (tmp == -1)return 1;
      else if (tmp == 0)ret = 0;
    }
    return ret;
  }
  int &ret = dpDebug[st1][st2][last];
  if (ret != -inf)return ret;
  if (__builtin_popcount(st1) == __builtin_popcount(st2)){//自分の番、評価値を最大化する。
    if (myp+dp[0][st1][st2][last] < opp)return -1;//負け
    ret = -1;
    rep(i,n){
    if ((1<<i)&st1)continue;
      int tmp=searchDebug(n,st1|(1<<i),st2,i,m,myp+m[i][last],opp,alpha,beta);
      if (tmp == -1)return 1;
      else if (tmp == 0)ret = 0;
    }
  }else {//相手の番、評価値を最小化する。
    if (myp > opp+dp[1][st1][st2][last])return -1;//負けが確定しているのでゲームを終了する
    ret = inf;
    rep(i,n){
      if ((1<<i)&st2)continue;
      int tmp=searchDebug(n,st1,st2|(1<<i),i,m,myp,opp+m[last][i],alpha,beta);
      if (tmp == -1)return 1;
      else if (tmp == 0)ret = 0;
    }
  }
  return ret;
}

main(){
  int n;
  int m[N][N];
  int f;
  while(cin>>n>>f && n){
    rep(i,n)rep(j,n)cin>>m[i][j];
    rep(ii,2)rep(i,(1<<n))rep(j,(1<<n))rep(k,n)dp[ii][i][j][k] = -inf;
    rep(i,(1<<n))rep(j,(1<<n))rep(k,n)dpDebug[i][j][k] = -inf;
    int tmp = precalc(n,0,0,0,-1,m);
    int tmp2 = precalc(n,1,0,0,-1,m);
    if (tmp + f < 0){//特殊ケース、先手の人はどうやっても勝てない
      cout << "Second" << endl;
      cout << 1 << endl;
      continue;
    }
    
    //int ans = search(n,0,0,-1,m,f,0,-inf/2,inf/2);/*alpha,betaは後でp適切な値に修正すること。*/
    int ans = search(n,0,0,-1,m,f,0,-inf,inf);/*alpha,betaは後でp適切な値に修正すること。*/
    int check = searchDebug(n,0,0,-1,m,f,0,0,0);
    //cout <<"tes " << getop(ans) << " " << check << endl;
    if (ans == 0){
      assert(check == 0);
      cout << "Draw" << endl;
      cout << 2*n << endl;//引き分けならあきらかに2N手かかる
    }else if (ans > 0){
      assert(check == 1);
      cout << "First" << endl;
      //cout << getop(ans) << endl;
      //cout << -ans << endl;
      cout << ans << endl;
    }else if (ans < 0){
      assert(check == -1);
      cout << "Second" << endl;
      //cout << getop(ans) << endl;
      cout << -ans << endl;
    }

    /*
    cout << "--------------debug" <<endl;
    cout << acut << " " << bcut << endl;
    cout << "----------------end" << endl;
    */
  }
  return 0;
}
accuracy: 0.11538461538461539
time_ms: 50
memory_kb: 0
final_rank: 9

code_snippet: #include<iostream>
#include<cassert>
#include<cmath>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)
const int N = 8;
const int inf = 10000000;
int dp[2][(1<<N)][(1<<N)][N];/*自分の選んだ場所、相手の選んだ場所、最後に選ばれた数字*/

/*
  最高の場合の自分と相手の点数の差を求めておく。
  探索時にこの差、で相手の点数に追いつけなければ負けが確定するので、その時点で打ち切りできるようになる。
  signが0の時は、自分は最善手、相手は最悪手を選ぶ。
  signが1の時は、自分は最悪手、相手は最善手を選ぶ。
*/
int precalc(int n,int sign,int st1,int st2,int last,const int m[N][N]){
  if (st1 == (1<<n)-1 && st1 == st2){
    return dp[sign][st1][st2][last] = 0;
  }
  if (last == -1){/*最初の手*/
    int ret;
    if (sign == 0)ret = -inf;
    else ret = inf;
    rep(i,n){
      int tmp = precalc(n,sign,1<<i,st2,i,m);
      if (sign == 0)ret = max(ret,-tmp);
      else if (sign == 1)ret = min(ret,-tmp);
    }
    return ret;
  }
  int &ret = dp[sign][st1][st2][last];
  if (ret != -inf)return ret;
  if (__builtin_popcount(st1) == __builtin_popcount(st2)){/*次の手は自分*/
    if (sign == 0)ret = -inf;
    else if (sign == 1)ret = inf;
    rep(i,n){
      if ((1<<i)&st1)continue;
      int tmp = precalc(n,sign,st1|(1<<i),st2,i,m);
      if (sign == 0)ret = max(ret,m[i][last] - tmp);
      else if (sign == 1)ret = min(ret,m[i][last]-tmp);
    }
  }else {
    if (sign == 0)ret = inf;
    else if (sign == 1)ret = -inf;
    rep(i,n){
      if ((1<<i)&st2)continue;
      int tmp = precalc(n,sign,st1,st2|(1<<i),i,m);
      if (sign == 0)ret = min(ret,m[last][i] - tmp);
      else if (sign == 1)ret = max(ret,m[last][i] - tmp);
    }
  }
  return ret;
}

/*
  評価値から手数を復元
*/
int getop(const int val){
  int ret = 0;
  if (val == 0){
    ret = val;
  }else if (val > 0){
    ret = val - inf;
  }else if (val < 0){
    ret = inf + val;
    ret *= -1;
  }
  return ret;
}

/*評価値から符号付き手数を復元*/
int getSignedOp(const int val){
  int ret = 0;
  if (val == 0){
    ret = val;
  }else if (val > 0){
    ret = inf - val;
  }else if (val < 0){
    ret = inf + val ;
  }
  return ret;
}

/*符号付き手数から次の符号付き手数を生成する*/
int getNextSignedOp(const int val){
  int ret = 0;
  if (val == 0){
    ret = val;
  }else if (val < 0){
    ret = val;
    ret--;
    ret *= -1;
  }else if (val > 0){
    ret = val;
    ret++;
    ret *= -1;
  }
  return ret;
}

/*
  符号付き手数から次の結果を計算する
*/
int update(const int ret,const int op){
  if (ret == -inf || ret == inf){
    return op;
  }
  if (op == 0){/*引き分け*/
    if (ret > 0)return ret;/*すでに勝つことが決まっているなら答えは変わらない*/
    else return 0;/*負けか引き分けなら引き分け*/
  }else if (op > 0){/*勝ち*/
    if (ret > 0)return min(ret,op);/*すでに勝つことが決まっているなら、最小の手数を返す*/
    else return op;/*負けか引き分けならopを返す*/
  }else if (op < 0){/*負け*/
    if (ret >= 0)return ret;/*価値か引き分けなら答えは変わらない*/
    else return min(ret,op);/*負けなら負けるまでの手数が大きい方を選ぶ*/
  }
  assert(false);
}

/*符号付き手数から評価値を返す*/
int getval(const int op){
  if (op == 0){
    return 0;
  }else if (op > 0){
    return inf - op;
  }else if (op < 0){
    return -(inf + -op);
  }
  assert(false);
}

/*
  ALPHA-BETAカットを用いた探索を行う。
  評価値は
  勝つときはinf-手数。
  引き分けなら0
  負なら -(inf+手数)
  を評価値として使う（解説通り）

  自分の番、評価値の最大化を目指す。
  相手の番、評価値の最小化を目指す。

  自分の番、親のノードの探索途中の評価値（相手の値）よりでかいものが出てきたとする。
  　　　　　この時、自分の番で選ばれるものを、相手が選ぶことがなくなるので枝刈りできる。
            （相手は最小になる手を選ぶのでここが選ばれることがなくなるのでもう見る必要がない）
  相手の番、親の最大値（自分の値）より小さいものが出てきたら終了。
  　　　　　（自分は、最大の値となるものを選ぶ。相手は最小となるものを選ぶ。このノードから探索を続けても、相手の評価値はより小さい値にしかならず、
  　　　　　　自分の番でこのノードが選ばれることがないのがわかる。

  返り値は評価値。
  内部の計算は手数で行おう。
*/

int acut = 0,bcut = 0;
/*
int search(int n,int st1,int st2,int last,const int m[N][N],int myp,int opp,int alpha,int beta){
  if (st1 == (1<<n)-1 && st1 == st2 ){
    return 0;//引き分け
  }
  int ret;
  if (last == -1){
    ret = -inf;
    rep(i,n){
      int tmp = search(n,(1<<i),st2,i,m,myp,opp,alpha,beta);
      int op = tmp;
      ret = max(ret,op);
    }
    return ret;
  }
  if (__builtin_popcount(st1) == __builtin_popcount(st2)){//自分の番、評価値を最大化する。
    if (myp+dp[0][st1][st2][last] < opp)return -(inf+1);//負け
    ret = -inf;
    rep(i,n){
      if ((1<<i)&st1)continue;
      int tmp=search(n,st1|(1<<i),st2,i,m,myp+m[i][last],opp,alpha,beta);
      int op = tmp;
      ret = max(ret,op);
    }
  }else {//相手の番、評価値を最小化する。
    if (myp > opp+dp[1][st1][st2][last])return -(inf+1);//負けが確定しているのでゲームを終了する
    ret = inf;
    rep(i,n){
      if ((1<<i)&st2)continue;
      int tmp=search(n,st1,st2|(1<<i),i,m,myp,opp+m[last][i],alpha,beta);
      int op = tmp;
      ret = min(ret,op);
    }
  }
  return getval(getNextSignedOp(getSignedOp(ret)));
}
*/

int search(int n,int st1,int st2,int last,const int m[N][N],int myp,int opp,int alpha,int beta){
  if (st1 == (1<<n)-1 && st1 == st2 ){
    if (myp > opp)return 1;
    else if (myp < opp)return -1;
    return 0;//引き分け
  }
  int ret = -inf;
  if (last == -1){
    rep(i,n){
      int tmp = search(n,(1<<i),st2,i,m,myp,opp,alpha,beta);
      int op = getNextSignedOp(tmp);
      ret = update(ret,op);
    }
    return ret;
  }
  if (__builtin_popcount(st1) == __builtin_popcount(st2)){//自分の番、評価値を最大化する。
    if (myp+dp[0][st1][st2][last] < opp)return -1;//負け
    rep(i,n){
      if ((1<<i)&st1)continue;
      int tmp=search(n,st1|(1<<i),st2,i,m,myp+m[i][last],opp,alpha,beta);
      int op = getNextSignedOp(tmp);
      ret = update(ret,op);
      
      alpha = max(alpha,getval(ret));
      if (alpha < beta){
	bcut++;
	break;
      }
    }
  }else {//相手の番、評価値を最小化する。
    if (myp > opp+dp[1][st1][st2][last])return -1;//負けが確定しているのでゲームを終了する
    rep(i,n){
      if ((1<<i)&st2)continue;
      int tmp=search(n,st1,st2|(1<<i),i,m,myp,opp+m[last][i],alpha,beta);
      int op = getNextSignedOp(tmp);
      ret = update(ret,op);
      beta = min(beta,getval(ret));
      if (alpha < beta){
	acut++;
	break;
      }
    }
  }
  return ret;
}


/*
  勝ち    1
  引き分け0
  負け　　-1
*/

int searchDebug(int n,int st1,int st2,int last,const int m[N][N],int myp,int opp,int alpha,int beta){
  if (st1 == (1<<n)-1 && st1 == st2 ){
    assert(myp == opp);
    return 0;//引き分け
  }
  if (last == -1){
    int ret = -1;
    rep(i,n){
      int tmp = searchDebug(n,(1<<i),st2,i,m,myp,opp,alpha,beta);
      if (tmp == -1)return 1;
      else if (tmp == 0)ret = 0;
    }
    return ret;
  }
  int ret = 0;
  if (__builtin_popcount(st1) == __builtin_popcount(st2)){//自分の番、評価値を最大化する。
    if (myp+dp[0][st1][st2][last] < opp)return -1;//負け
    ret = -1;
    rep(i,n){
    if ((1<<i)&st1)continue;
      int tmp=searchDebug(n,st1|(1<<i),st2,i,m,myp+m[i][last],opp,alpha,beta);
      if (tmp == -1)return 1;
      else if (tmp == 0)ret = 0;
    }
  }else {//相手の番、評価値を最小化する。
    if (myp > opp+dp[1][st1][st2][last])return -1;//負けが確定しているのでゲームを終了する
    ret = inf;
    rep(i,n){
      if ((1<<i)&st2)continue;
      int tmp=searchDebug(n,st1,st2|(1<<i),i,m,myp,opp+m[last][i],alpha,beta);
      if (tmp == -1)return 1;
      else if (tmp == 0)ret = 0;
    }
  }
  return ret;
}

main(){
  int n;
  int m[N][N];
  int f;
  while(cin>>n>>f && n){
    rep(i,n)rep(j,n)cin>>m[i][j];
    rep(ii,2)rep(i,(1<<n))rep(j,(1<<n))rep(k,n)dp[ii][i][j][k] = -inf;
    int tmp = precalc(n,0,0,0,-1,m);
    int tmp2 = precalc(n,1,0,0,-1,m);
    if (tmp + f < 0){//特殊ケース、先手の人はどうやっても勝てない
      cout << "Second" << endl;
      cout << 1 << endl;
      continue;
    }
    
    //int ans = search(n,0,0,-1,m,f,0,-inf/2,inf/2);/*alpha,betaは後でp適切な値に修正すること。*/
    int ans = search(n,0,0,-1,m,f,0,-inf,inf);/*alpha,betaは後でp適切な値に修正すること。*/
    //int check = searchDebug(n,0,0,-1,m,f,0,0,0);
    //cout <<"tes " << getop(ans) << " " << check << endl;
    if (ans == 0){
      cout << "Draw" << endl;
      cout << 2*n << endl;//引き分けならあきらかに2N手かかる
    }else if (ans > 0){
      cout << "First" << endl;
      //cout << getop(ans) << endl;
      //cout << -ans << endl;
      cout << ans << endl;
    }else if (ans < 0){
      cout << "Second" << endl;
      //cout << getop(ans) << endl;
      cout << -ans << endl;
    }

    /*
    cout << "--------------debug" <<endl;
    cout << acut << " " << bcut << endl;
    cout << "----------------end" << endl;
    */
  }
  return 0;
}
accuracy: 0.11538461538461539
time_ms: 20
memory_kb: 4932
final_rank: 10

code_snippet: #include<iostream>
#include<cassert>
#include<cmath>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)
const int N = 8;
const int inf = 10000000;
int dp[2][(1<<N)][(1<<N)][N];/*自分の選んだ場所、相手の選んだ場所、最後に選ばれた数字*/

/*
  最高の場合の自分と相手の点数の差を求めておく。
  探索時にこの差、で相手の点数に追いつけなければ負けが確定するので、その時点で打ち切りできるようになる。
  signが0の時は、自分は最善手、相手は最悪手を選ぶ。
  signが1の時は、自分は最悪手、相手は最善手を選ぶ。
*/
int precalc(int n,int sign,int st1,int st2,int last,const int m[N][N]){
  if (st1 == (1<<n)-1 && st1 == st2){
    return dp[sign][st1][st2][last] = 0;
  }
  if (last == -1){/*最初の手*/
    int ret;
    if (sign == 0)ret = -inf;
    else ret = inf;
    rep(i,n){
      int tmp = precalc(n,sign,1<<i,st2,i,m);
      if (sign == 0)ret = max(ret,-tmp);
      else if (sign == 1)ret = min(ret,-tmp);
    }
    return ret;
  }
  int &ret = dp[sign][st1][st2][last];
  if (ret != -inf)return ret;
  if (__builtin_popcount(st1) == __builtin_popcount(st2)){/*次の手は自分*/
    if (sign == 0)ret = -inf;
    else if (sign == 1)ret = inf;
    rep(i,n){
      if ((1<<i)&st1)continue;
      int tmp = precalc(n,sign,st1|(1<<i),st2,i,m);
      if (sign == 0)ret = max(ret,m[i][last] - tmp);
      else if (sign == 1)ret = min(ret,m[i][last]-tmp);
    }
  }else {
    if (sign == 0)ret = inf;
    else if (sign == 1)ret = -inf;
    rep(i,n){
      if ((1<<i)&st2)continue;
      int tmp = precalc(n,sign,st1,st2|(1<<i),i,m);
      if (sign == 0)ret = min(ret,m[last][i] - tmp);
      else if (sign == 1)ret = max(ret,m[last][i] - tmp);
    }
  }
  return ret;
}

/*
  評価値から手数を復元
*/
int getop(const int val){
  int ret = 0;
  if (val == 0){
    ret = val;
  }else if (val > 0){
    ret = val - inf;
  }else if (val < 0){
    ret = inf + val;
    ret *= -1;
  }
  return ret;
}

/*評価値から符号付き手数を復元*/
int getSignedOp(const int val){
  int ret = 0;
  if (val == 0){
    ret = val;
  }else if (val > 0){
    ret = inf - val;
  }else if (val < 0){
    ret = inf + val ;
  }
  return ret;
}

/*符号付き手数から次の符号付き手数を生成する*/
int getNextSignedOp(const int val){
  int ret = 0;
  if (val == 0){
    ret = val;
  }else if (val < 0){
    ret = val;
    ret--;
    ret *= -1;
  }else if (val > 0){
    ret = val;
    ret++;
    ret *= -1;
  }
  return ret;
}

/*
  符号付き手数から次の結果を計算する
*/
int update(const int ret,const int op){
  if (ret == -inf || ret == inf){
    return op;
  }
  if (op == 0){/*引き分け*/
    if (ret > 0)return ret;/*すでに勝つことが決まっているなら答えは変わらない*/
    else return 0;/*負けか引き分けなら引き分け*/
  }else if (op > 0){/*勝ち*/
    if (ret > 0)return min(ret,op);/*すでに勝つことが決まっているなら、最小の手数を返す*/
    else return op;/*負けか引き分けならopを返す*/
  }else if (op < 0){/*負け*/
    if (ret >= 0)return ret;/*価値か引き分けなら答えは変わらない*/
    else return min(ret,op);/*負けなら負けるまでの手数が大きい方を選ぶ*/
  }
  assert(false);
}

/*手数から評価値を返す*/
int getval(const int op){
  if (op == 0){
    return 0;
  }else if (op > 0){
    return inf - op;
  }else if (op < 0){
    return -(inf + -op);
  }
  assert(false);
}

/*
  ALPHA-BETAカットを用いた探索を行う。
  評価値は
  勝つときはinf-手数。
  引き分けなら0
  負なら -(inf+手数)
  を評価値として使う（解説通り）

  自分の番、評価値の最大化を目指す。
  相手の番、評価値の最小化を目指す。

  自分の番、親のノードの探索途中の評価値（相手の値）よりでかいものが出てきたとする。
  　　　　　この時、自分の番で選ばれるものを、相手が選ぶことがなくなるので枝刈りできる。
            （相手は最小になる手を選ぶのでここが選ばれることがなくなるのでもう見る必要がない）
  相手の番、親の最大値（自分の値）より小さいものが出てきたら終了。
  　　　　　（自分は、最大の値となるものを選ぶ。相手は最小となるものを選ぶ。このノードから探索を続けても、相手の評価値はより小さい値にしかならず、
  　　　　　　自分の番でこのノードが選ばれることがないのがわかる。

  返り値は評価値。
  内部の計算は手数で行おう。
*/

int acut = 0,bcut = 0;
/*
int search(int n,int st1,int st2,int last,const int m[N][N],int myp,int opp,int alpha,int beta){
  if (st1 == (1<<n)-1 && st1 == st2 ){
    return 0;//引き分け
  }
  int ret;
  if (last == -1){
    ret = -inf;
    rep(i,n){
      int tmp = search(n,(1<<i),st2,i,m,myp,opp,alpha,beta);
      int op = tmp;
      ret = max(ret,op);
    }
    return ret;
  }
  if (__builtin_popcount(st1) == __builtin_popcount(st2)){//自分の番、評価値を最大化する。
    if (myp+dp[0][st1][st2][last] < opp)return -(inf+1);//負け
    ret = -inf;
    rep(i,n){
      if ((1<<i)&st1)continue;
      int tmp=search(n,st1|(1<<i),st2,i,m,myp+m[i][last],opp,alpha,beta);
      int op = tmp;
      ret = max(ret,op);
    }
  }else {//相手の番、評価値を最小化する。
    if (myp > opp+dp[1][st1][st2][last])return -(inf+1);//負けが確定しているのでゲームを終了する
    ret = inf;
    rep(i,n){
      if ((1<<i)&st2)continue;
      int tmp=search(n,st1,st2|(1<<i),i,m,myp,opp+m[last][i],alpha,beta);
      int op = tmp;
      ret = min(ret,op);
    }
  }
  return getval(getNextSignedOp(getSignedOp(ret)));
}
*/


int search(int n,int st1,int st2,int last,const int m[N][N],int myp,int opp,int alpha,int beta){
  if (st1 == (1<<n)-1 && st1 == st2 ){
    assert(myp == opp);
    return 0;//引き分け
  }
  int ret = -inf;
  if (last == -1){
    rep(i,n){
      int tmp = search(n,(1<<i),st2,i,m,myp,opp,alpha,beta);
      int op = getNextSignedOp(tmp);
      ret = update(ret,op);
    }
    return ret;
  }
  if (__builtin_popcount(st1) == __builtin_popcount(st2)){//自分の番、評価値を最大化する。
    if (myp+dp[0][st1][st2][last] < opp)return -1;//負け
    rep(i,n){
      if ((1<<i)&st1)continue;
      int tmp=search(n,st1|(1<<i),st2,i,m,myp+m[i][last],opp,alpha,beta);
      int op = getNextSignedOp(tmp);
      ret = update(ret,op);
      
      alpha = max(alpha,getval(ret));
      if (alpha <= beta){
	bcut++;
	break;
      }
    }
  }else {//相手の番、評価値を最小化する。
    if (myp > opp+dp[1][st1][st2][last])return -1;//負けが確定しているのでゲームを終了する
    rep(i,n){
      if ((1<<i)&st2)continue;
      int tmp=search(n,st1,st2|(1<<i),i,m,myp,opp+m[last][i],alpha,beta);
      int op = getNextSignedOp(tmp);
      ret = update(ret,op);
      beta = min(beta,getval(ret));
      if (alpha <= beta){
	acut++;
	break;
      }
    }
  }
  return ret;
}


/*
  勝ち    1
  引き分け0
  負け　　-1
*/

int searchDebug(int n,int st1,int st2,int last,const int m[N][N],int myp,int opp,int alpha,int beta){
  if (st1 == (1<<n)-1 && st1 == st2 ){
    assert(myp == opp);
    return 0;//引き分け
  }
  if (last == -1){
    int ret = -1;
    rep(i,n){
      int tmp = searchDebug(n,(1<<i),st2,i,m,myp,opp,alpha,beta);
      if (tmp == -1)return 1;
      else if (tmp == 0)ret = 0;
    }
    return ret;
  }
  int ret = 0;
  if (__builtin_popcount(st1) == __builtin_popcount(st2)){//自分の番、評価値を最大化する。
    if (myp+dp[0][st1][st2][last] < opp)return -1;//負け
    ret = -1;
    rep(i,n){
    if ((1<<i)&st1)continue;
      int tmp=searchDebug(n,st1|(1<<i),st2,i,m,myp+m[i][last],opp,alpha,beta);
      if (tmp == -1)return 1;
      else if (tmp == 0)ret = 0;
    }
  }else {//相手の番、評価値を最小化する。
    if (myp > opp+dp[1][st1][st2][last])return -1;//負けが確定しているのでゲームを終了する
    ret = inf;
    rep(i,n){
      if ((1<<i)&st2)continue;
      int tmp=searchDebug(n,st1,st2|(1<<i),i,m,myp,opp+m[last][i],alpha,beta);
      if (tmp == -1)return 1;
      else if (tmp == 0)ret = 0;
    }
  }
  return ret;
}

main(){
  int n;
  int m[N][N];
  int f;
  while(cin>>n>>f && n){
    rep(i,n)rep(j,n)cin>>m[i][j];
    rep(ii,2)rep(i,(1<<n))rep(j,(1<<n))rep(k,n)dp[ii][i][j][k] = -inf;
    int tmp = precalc(n,0,0,0,-1,m);
    int tmp2 = precalc(n,1,0,0,-1,m);
    if (tmp + f < 0){//特殊ケース、先手の人はどうやっても勝てない
      cout << "Second" << endl;
      cout << 1 << endl;
      continue;
    }
    
    //int ans = search(n,0,0,-1,m,f,0,-inf/2,inf/2);/*alpha,betaは後でp適切な値に修正すること。*/
    int ans = search(n,0,0,-1,m,f,0,-inf,inf);/*alpha,betaは後でp適切な値に修正すること。*/
    //int check = searchDebug(n,0,0,-1,m,f,0,0,0);
    //cout <<"tes " << getop(ans) << " " << check << endl;
    if (ans == 0){
      cout << "Draw" << endl;
      cout << 2*n << endl;//引き分けならあきらかに2N手かかる
    }else if (ans > 0){
      cout << "First" << endl;
      //cout << getop(ans) << endl;
      //cout << -ans << endl;
      cout << ans << endl;
    }else if (ans < 0){
      cout << "Second" << endl;
      //cout << getop(ans) << endl;
      cout << -ans << endl;
    }

    /*
    if (ans == 0 || ans == 2*n){
      cout << "Draw" << endl;
      cout << 2*n << endl;//引き分けならあきらかに2N手かかる
    }else if (ans > 0){
      cout << "First" << endl;
      cout << ans << endl;
    }else if (ans < 0){
      cout << "Second" << endl;
      cout << -(ans) << endl;
    }
    */
    /*
    cout << "--------------debug" <<endl;
    cout << acut << " " << bcut << endl;
    cout << "----------------end" << endl;
    */
  }
  return 0;
}
accuracy: 0.11538461538461539
time_ms: 20
memory_kb: 0
final_rank: 8