Problem:
MinimumCostPath

NxNの方眼がある。

(N=3の場合の図)

隣接するマス目に移動するにはコストが1かかる。ただし、斜めに移動することは出来ない。
また障害物があるマス目がM個あり、そのマスに入ることは許されない。
マス(1, 1)からマス(N, N)に最小のコストで移動する方法は何通りあるか。
答えは大きくなることがありうるので、1000000009(=109+9)でMODを取って出力せよ。

Input

入力は以下の形式で与えられる

N M
X1 Y1
X2 Y2
……
XM YM

Xi, Yiは(Xi, Yi)に障害物があることを表す

Constraints

2 ≤ N ≤ 106

0 ≤ M ≤ 50

1 ≤ Xi , Yi ≤ N

i ≠ jならば (Xi, Yi) ≠ (Xj, Yj)

(Xi, Yi) ≠ (1, 1)

(Xi, Yi) ≠ (N, N)

Output

1行に経路の総数を出力せよ。ただし、マス(1, 1)からマス(N, N)に移動する経路が存在しない場合は0と出力せよ。

Sample Input 1

3 0

Output for the Sample Input 1

6

以下の図に対応する。

Sample Input 2

3 1
2 2

Output for the Sample Input 2

2

以下の図に対応する。

Sample Input 3

5 8
4 3
2 1
4 2
4 4
3 4
2 2
2 4
1 4

Output for the Sample Input 3

1

以下の図に対応する。

Sample Input 4

1000 10
104 87
637 366
393 681
215 604
707 876
943 414
95 327
93 415
663 596
661 842

Output for the Sample Input 4

340340391

Sample Input 5

2 2
1 2
2 1

Output for the Sample Input 5

0

Solution in C++14 (judge verdict: Accepted)

#include<bits/stdc++.h>
using namespace std;
using Int = long long;
using ll = long long;

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

const Int MOD = 1e9+9;

Int add(Int a,Int b){
  return (a+b)%MOD;
}
Int sub(Int a,Int b){
  return (a+MOD-b)%MOD;
}
Int mul(Int a,Int b){
  return (1LL*a*b)%MOD;
}
Int pow(Int a,Int b){
  Int r=1;
  while(b){
    if(b&1) r=mul(r,a);
    a=mul(a,a);
    b>>=1;
  }
  return r;
}
Int inv(Int a){
  return pow(a,MOD-2);
}

const Int MAX = 4e6+100;
Int fact[MAX],finv[MAX],invs[MAX];
void init(){
  fact[0]=1;
  for(Int i=1;i<MAX;i++)
    fact[i]=mul(fact[i-1],i);

  finv[MAX-1]=inv(fact[MAX-1]);
  for(Int i=MAX-1;i>0;i--)
    finv[i-1]=mul(finv[i],i);

  invs[0]=0;
  for(Int i=1;i<MAX;i++)
    invs[i]=mul(finv[i],fact[i-1]);
}

Int C(Int n,Int k){
  if(k<0||k>n) return 0;
  return mul(fact[n],mul(finv[n-k],finv[k]));
}

const Int SZ = 111;
Int wy[SZ][SZ];
Int zy[SZ][SZ];
Int ds[SZ][SZ];
Int wl[SZ][SZ];

signed main(){
  cin.tie(0);
  ios::sync_with_stdio(0);

  Int n,m;
  cin>>n>>m;
  vector<Int> xs(m),ys(m);
  for(Int i=0;i<m;i++) cin>>xs[i]>>ys[i];

  init();

  Int dy[]={0,0,1,-1};
  Int dx[]={1,-1,0,0};

  auto bfs=[&](auto &in){
    memset(wy, 0,sizeof(wy));
    memset(ds,-1,sizeof(ds));

    using P = pair<Int, Int>;
    queue<P> que;
    wy[1][1]=1;
    ds[1][1]=0;
    que.emplace(1,1);

    while(!que.empty()){
      Int y,x;
      tie(y,x)=que.front();que.pop();
      for(Int k=0;k<4;k++){
        Int ny=y+dy[k],nx=x+dx[k];
        if(!in(ny,nx)||wl[ny][nx]) continue;
        if(ds[ny][nx]<0){
          ds[ny][nx]=ds[y][x]+1;
          wy[ny][nx]=wy[y][x];
          que.emplace(ny,nx);
          continue;
        }
        if(ds[ny][nx]<ds[y][x]+1) continue;
        if(ds[ny][nx]>ds[y][x]+1){
          ds[ny][nx]=ds[y][x]+1;
          wy[ny][nx]=0;
        }
        wy[ny][nx]=add(wy[ny][nx],wy[y][x]);
      }
    }
  };

  if(n<SZ-10){
    auto in=[&](Int y,Int x){
      return 0<y&&y<=n&&0<x&&x<=n;
    };

    memset(wl, 0,sizeof(wl));
    for(Int i=0;i<m;i++)
      wl[ys[i]][xs[i]]=1;

    bfs(in);
    cout<<wy[n][n]<<endl;
    return 0;
  }

  const Int LEN=SZ-20;
  auto in=[&](Int y,Int x){
    return 0<y&&y<=LEN&&0<x&&x<=LEN;
  };

  // from (n, n)
  {
    memset(wl, 0,sizeof(wl));
    for(Int i=0;i<m;i++){
      Int y=n-xs[i]+1;
      Int x=n-ys[i]+1;
      if(in(y,x)) wl[y][x]=1;
    }

    bfs(in);

    for(Int i=0;i<SZ;i++)
      for(Int j=0;j<SZ;j++)
        zy[i][j]=wy[i][j];

    Int res=-1;
    for(Int y=1;y<LEN;y++){
      Int x=LEN-y;
      if(ds[y][x]<0) continue;
      if(res<0) res=ds[y][x];
      chmin(res,ds[y][x]);
    }
    if(res<0){
      cout<<0<<endl;
      return 0;
    }
    for(Int y=1;y<LEN;y++){
      Int x=LEN-y;
      if(ds[y][x]==res){
        ys.emplace_back(n-x+1);
        xs.emplace_back(n-y+1);
      }
    }
  }
  // from (1, 1)
  {
    memset(wl, 0,sizeof(wl));
    for(Int i=0;i<m;i++)
      if(in(ys[i],xs[i]))
        wl[ys[i]][xs[i]]=1;

    bfs(in);

    Int res=-1;
    for(Int y=1;y<LEN;y++){
      Int x=LEN-y;
      if(ds[y][x]<0) continue;
      if(res<0) res=ds[y][x];
      chmin(res,ds[y][x]);
    }
    if(res<0){
      cout<<0<<endl;
      return 0;
    }
    for(Int y=1;y<LEN;y++){
      Int x=LEN-y;
      if(ds[y][x]==res){
        ys.emplace_back(y);
        xs.emplace_back(x);
      }
    }
  }


  Int sz=xs.size();
  using P = pair<Int, Int>;
  vector<P> vp;
  for(Int i=0;i<sz;i++){
    if(xs[i]+ys[i]<LEN||xs[i]+ys[i]>2*n-LEN+2) continue;
    vp.emplace_back(xs[i]+ys[i],ys[i]);
  }

  sz=vp.size();
  sort(vp.begin(),vp.end());
  for(Int i=0;i<sz;i++){
    xs[i]=vp[i].first-vp[i].second;
    ys[i]=vp[i].second;
  }

  vector<Int> dp1(sz,0);
  vector<Int> dp2(sz,0);
  for(Int i=0;i<sz;i++)
    if(xs[i]+ys[i]==LEN)
      dp2[i]=wy[ys[i]][xs[i]];

  for(Int i=0;i<sz;i++){
    for(Int j=i+1;j<sz;j++){
      Int dx=xs[j]-xs[i];
      Int dy=ys[j]-ys[i];
      if(dx<0||dy<0) continue;
      dp1[j]=add(dp1[j],mul(dp2[i],C(dx+dy,dx)));
      dp2[j]=add(dp2[j],mul(dp1[i],C(dx+dy,dx)));
    }
  }

  Int ans=0;
  for(Int i=0;i<sz;i++){
    if(xs[i]+ys[i]==2*n-LEN+2){
      ans=add(ans,mul(dp1[i],zy[n-xs[i]+1][n-ys[i]+1]));
      ans=sub(ans,mul(dp2[i],zy[n-xs[i]+1][n-ys[i]+1]));
    }
  }

  cout<<ans<<endl;
  return 0;
}