Problem:
問題文
以下の条件を満たす整数列 $X_1, X_2, ..., X_N$ の個数を求めよ。
任意の整数 $i$ ($1 \leq i \leq N$)に対して、$X_j=i$ となる $j$ ($1 \leq j \leq N$)が存在する。
$X_s = t$
$X_{a_i} < X_{b_i}$ ($1 \leq i \leq C$)
入力
入力は以下の形式に従う。与えられる数は全て整数である。
$N$ $C$ $s$ $t$
$a_1$ $b_1$
$a_2$ $b_2$
$...$
$a_C$ $b_C$
制約
$1 \leq N \leq 2000$
$0 \leq C \leq N$
$1 \leq s \leq N$
$1 \leq t \leq N$
$1 \leq a_i \leq N$
$1 \leq b_i \leq N$
$a_i \neq b_i$
$i \neq j$ ならば $a_i \neq a_j$
出力
条件を満たす数列の個数を $10^9+7$ で割った余りを1行に出力せよ(条件を満たす数列の個数がたかだか有限個しかないことは簡単に示される)。
Sample Input 1
3 1 1 1
1 3
Output for the Sample Input 1
2
$\{X_1, X_2, X_3\} = \{1, 2, 3\}, \{1, 3, 2\}$ の2つが条件を満たす。
Sample Input 2
4 2 1 1
2 3
3 2
Output for the Sample Input 2
0
$X_2<X_3$ かつ $X_3<X_2$ を満たす数列は存在しない。

Submitted solutions:

code_snippet: #include <cstdio>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;

typedef long long int64;

const int MAX_N = 2000 + 1;
const int64 MOD = (int64)(1e9 + 7);

int N, C, target, ord;

int parent[MAX_N+1];
vector<int> graph[MAX_N+1];

int V[MAX_N+1];
int S[MAX_N+1];
int64 T[MAX_N+1];

int64 dp[MAX_N+1][MAX_N+1];
bool visited[MAX_N + 1];
int64 comb[MAX_N+1][MAX_N+1];

void init(){
	scanf("%d%d%d%d", &N, &C, &target, &ord);
	ord = N - ord + 1;
	++N;
	parent[0] = -1;
	for(int i=0; i<C; i++){
		int a, b;
		scanf("%d%d", &a, &b);
		parent[a] = b;
		graph[b].push_back(a);
	}

	for(int i=0; i<N; i++)if(parent[i] == 0){
		graph[0].push_back(i);
	}

	for(int i=0; i<=N; i++){
		comb[i][i] = comb[i][0] = 1;
		for(int j=1; j<i; j++){
			comb[i][j] = ( comb[i-1][j-1] + comb[i-1][j] ) % MOD;
		}
	}
}

void calc(int v){
	T[v] = S[v] = 1;
	for(int i=0; i<(int)graph[v].size(); ++i){
		const int u = graph[v][i];
		calc(u);
		S[v] += S[u];
	}

	int total = S[v] - 1;
	for(int i=0; i<(int)graph[v].size(); i++){
		const int u = graph[v][i];
		T[v] = T[v] * comb[total][S[u]] % MOD * T[u] % MOD;
		total -= S[u];
	}
}

int solve(){
	calc(0);
	if(S[0] != N){
		return 0;
	}

	const int dummy = N;
	S[dummy] = 0;
	parent[dummy] = target;

	int depth = 0;
	for(int v = target; v!=-1 ;V[depth++]=v, v=parent[v]);
	reverse(V, V+depth);
	V[depth] = dummy;

	for(int i=0; i<depth; i++){
		int cur = V[i], nxt = V[i+1], all = N - S[nxt];
		int64 sum = 0, prod = 1;
		int total = S[cur] - S[nxt] - 1;
		for(int j=0; j<(int)graph[cur].size(); j++){
			const int u = graph[cur][j];
			if(nxt != u){
				prod = prod * T[u] % MOD * comb[total][S[u]] % MOD;
				total -= S[u];
			}
		}
		if(i == 0){
			dp[0][0] = prod;
			continue;
		}
		for(int j=1; j<N; j++){
			sum = (sum + dp[i-1][j-1]) % MOD;
			int rem = all - j - 1, child = S[cur] - S[nxt] - 1;
			if(rem >= child && rem >= 0 && child >= 0){
				dp[i][j] = sum * comb[rem][child] % MOD * prod % MOD;
			}
		}
	}

	return (int)dp[depth-1][ord];
}

int main(){
	init();
	printf("%d\n", solve());

	return 0;
}
accuracy: 1
time_ms: 170
memory_kb: 52000
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)
typedef long long ll;
const ll mod = 1e9 + 7;
const int N = 2010;

//loop finding begin
vector<int> loopedge[N];
int loopvis[N];
bool loopFindingDfs(int u){
  if (loopvis[u] == 2)return false;
  if (loopvis[u] == 1)return true;
  loopvis[u]=1;
  rep(i,(int)loopedge[u].size()){
    if (loopFindingDfs(loopedge[u][i]))return true;
  }
  loopvis[u]=2;
  return false;
}
bool hasLoop(int n){
  rep(i,n)loopvis[i]=0;
  rep(i,n){
    if (loopvis[i] == 0 && loopFindingDfs(i))return true;
  }
  return false;
}
//loop finding end

ll comb[N][N];
void precalc(){
  comb[0][0] = 1;
  REP(i,1,N){
    comb[i][0] = comb[i][i] = 1;
    REP(j,1,i)comb[i][j] = (comb[i-1][j] + comb[i-1][j-1]) % mod;
  }
}

//solver
vector<int> edge[N];
int child[N];//子ノードの数
int req[N];//X[i]を子ノードとして持つなら、そのノードのインデックスを保持する。
int maxnum[N];//X[i]を子ノードとして持つとき、Xi未満の値を最大どのくらい持っていいのか
int reqnum;//X[i]以下のノードの数。
//子ノードの数を数え上げる。メモ化なし
int countChild(int now){
  int ret = 1;
  rep(i,(int)edge[now].size()){
    ret += countChild(edge[now][i]);
  }
  return child[now] = ret;
}

//X[i]以下のノードの数と、xi以下に遷移するノードの番号を記録しておく。
bool countReq(int now,const int s,bool childOfXs){
  req[now] = -1;
  bool ret = (now == s);
  rep(i,edge[now].size()){
    bool tmp = countReq(edge[now][i],s,childOfXs|(now == s));
    if (tmp)req[now] = i;
    ret |= tmp;
  }
  if (now == s)reqnum = child[now] -1;
  return ret;
}

//xs以下のノードが最大何個まで許容されるかを数える
int countXs(int now,int s){
  if (now == s)return maxnum[now] = child[now] - 1;
  if (req[now] == -1)return child[now];
  int ret = 0;
  maxnum[now] = 0;
  rep(i,edge[now].size()){
    int &next = edge[now][i];
    if (req[now] != i)maxnum[now] += child[next];
    else maxnum[now] += countXs(next,s);
  }
  return maxnum[now];
}

/*
  現在のノード、xs以下のノードの数
  xsを子ノードとして持たない場合はxs=0を代入してしまう
*/
ll dp[N][N];
int solveRec(int now,int xs,int s){
  if (req[now] == -1)xs = 0;
  ll &ret = dp[now][xs];
  if (ret != -1)return ret;
  ret = 1;
  int num = child[now]-1;
  //xsを子ノードとして持つノードから処理していく。
  if (req[now] != -1){
    ret = 0;
    int &next = edge[now][req[now]];
    REP(i,reqnum,maxnum[next]+1){
      if (xs < i)break;
      int larger = child[now] - xs -2;//tより大きい,child[now] -xs -(自分+t (1+1) )
      int konode = child[next]-1;//konode > xi
      konode -= i;
      if (konode > larger)continue;

      ll tmp = solveRec(next,i,s);
      tmp *= comb[xs][i];//xs以下のノードからi個えらぶ。
      tmp %= mod;
      tmp *= comb[larger][konode];//
      ret += tmp;
      ret %= mod;
    }
    num -= child[next];
  }
  rep(i,edge[now].size()){
    if (req[now] == i)continue;//このノードはもう処理したので無視する
    int & next = edge[now][i];
    ll tmp = solveRec(next,0,s);
    tmp *= comb[num][child[next]];
    tmp %= mod;
    num -= child[next];
    ret *= tmp;
    ret %= mod;
  }
  return ret;
}

int solve(int n,int s,int t){
  countChild(0);
  countReq(0,s,false);
  countXs(0,s);
  ll ret = solveRec(0,t-1,s);
  return ret;
}


main(){
  precalc();
  int n,c,t,s;
  static bool hasParent[N];
  while(cin>>n>>c>>s>>t && n){
    vector<pair<int,int> > cond;
    rep(i,n){
      loopedge[i].clear();
    }
    rep(i,n+1){
      rep(j,n+1)dp[i][j] = -1;
      hasParent[i] = false;
      edge[i].clear();
      reqnum = 0;
    }
    rep(i,c){
      int a,b;
      cin>>a>>b;
      //擬似的な親としてx0を追加する。こいつは、ルートになっているすべてのノードより大きい必要があるぽよ。
      edge[b].push_back(a);
      hasParent[a] = true;
      a--;b--;
      cond.push_back(make_pair(a,b));
      loopedge[b].push_back(a);
    }
    n++;
    REP(i,1,n){
      if (!hasParent[i])edge[0].push_back(i);
    }
    if (hasLoop(n)){cout << 0 << endl;continue;}
    cout << solve(n,s,t) << endl;
  }
  return 0;
}
accuracy: 1
time_ms: 50
memory_kb: 49000
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)
typedef long long ll;
const ll mod = 1e9 + 7;
const int N = 2010;

//loop finding begin
vector<int> loopedge[N];
int loopvis[N];
bool loopFindingDfs(int u){
  if (loopvis[u] == 2)return false;
  if (loopvis[u] == 1)return true;
  loopvis[u]=1;
  rep(i,(int)loopedge[u].size()){
    if (loopFindingDfs(loopedge[u][i]))return true;
  }
  loopvis[u]=2;
  return false;
}
bool hasLoop(int n){
  rep(i,n)loopvis[i]=0;
  rep(i,n){
    if (loopvis[i] == 0 && loopFindingDfs(i))return true;
  }
  return false;
}
//loop finding end

/*
  brute force solver
  condition x[first] < x[second]
  x[s] = t
*/
//--------------------------------------------------
int bf(int n,vector<pair<int,int> > &cond,int s,int t){
  int x[n];
  int ret = 0;
  rep(i,n)x[i] = i + 1;
  do{
    if (x[s] != t)continue;
    rep(i,cond.size()){
      if (x[cond[i].first] > x[cond[i].second])goto end;
    }
    ret++;
  end:;
  }while(next_permutation(x,x+n));
  return ret;
}
//--------------------------------------------------

ll comb[N][N];
void precalc(){
  comb[0][0] = 1;
  REP(i,1,N){
    comb[i][0] = comb[i][i] = 1;
    REP(j,1,i)comb[i][j] = (comb[i-1][j] + comb[i-1][j-1]) % mod;
  }
}

//solver
vector<int> edge[N];
int child[N];//子ノードの数
int req[N];//X[i]を子ノードとして持つなら、そのノードのインデックスを保持する。
int maxnum[N];//X[i]を子ノードとして持つとき、Xi未満の値を最大どのくらい持っていいのか
int reqnum;//X[i]以下のノードの数。
//子ノードの数を数え上げる。メモ化なし
int countChild(int now){
  int ret = 1;
  rep(i,(int)edge[now].size()){
    ret += countChild(edge[now][i]);
  }
  return child[now] = ret;
}

//X[i]以下のノードの数と、xi以下に遷移するノードの番号を記録しておく。
bool countReq(int now,const int s,bool childOfXs){
  req[now] = -1;
  bool ret = (now == s);
  rep(i,edge[now].size()){
    bool tmp = countReq(edge[now][i],s,childOfXs|(now == s));
    if (tmp)req[now] = i;
    ret |= tmp;
  }
  if (now == s)reqnum = child[now] -1;
  return ret;
}

//xs以下のノードが最大何個まで許容されるかを数える
int countXs(int now,int s){
  if (now == s)return maxnum[now] = child[now] - 1;
  if (req[now] == -1)return child[now];
  int ret = 0;
  maxnum[now] = 0;
  rep(i,edge[now].size()){
    int &next = edge[now][i];
    if (req[now] != i)maxnum[now] += child[next];
    else maxnum[now] += countXs(next,s);
  }
  return maxnum[now];
}

/*
  現在のノード、xs以下のノードの数
  xsを子ノードとして持たない場合はxs=0を代入してしまう
*/
ll dp[N][N];
int solveRec(int now,int xs,int s){
  if (req[now] == -1)xs = 0;
  ll &ret = dp[now][xs];
  if (ret != -1)return ret;
  ret = 1;
  int num = child[now]-1;
  //xsを子ノードとして持つノードから処理していく。
  if (req[now] != -1){
    ret = 0;
    int &next = edge[now][req[now]];
    REP(i,reqnum,maxnum[next]+1){
      if (xs < i)break;
      int larger = child[now] - xs -2;//tより大きい,child[now] -xs -(自分+t (1+1) )
      int konode = child[next]-1;//konode > xi
      konode -= i;
      if (konode > larger)continue;

      ll tmp = solveRec(next,i,s);
      tmp *= comb[xs][i];//xs以下のノードからi個えらぶ。
      tmp %= mod;
      tmp *= comb[larger][konode];//
      ret += tmp;
      ret %= mod;
    }
    num -= child[next];
  }
  rep(i,edge[now].size()){
    if (req[now] == i)continue;//このノードはもう処理したので無視する
    int & next = edge[now][i];
    ll tmp = solveRec(next,0,s);
    tmp *= comb[num][child[next]];
    tmp %= mod;
    num -= child[next];
    ret *= tmp;
    ret %= mod;
  }
  return ret;
}

int solve(int n,int s,int t){
  countChild(0);
  countReq(0,s,false);
  countXs(0,s);
  ll ret = solveRec(0,t-1,s);
  return ret;
}


main(){
  precalc();
  int n,c,t,s;
  static bool hasParent[N];
  while(cin>>n>>c>>s>>t && n){
    vector<pair<int,int> > cond;
    rep(i,n){
      loopedge[i].clear();
    }
    rep(i,n+1){
      rep(j,n+1)dp[i][j] = -1;
      hasParent[i] = false;
      edge[i].clear();
      reqnum = 0;
    }
    rep(i,c){
      int a,b;
      cin>>a>>b;
      //擬似的な親としてx0を追加する。こいつは、ルートになっているすべてのノードより大きい必要があるぽよ。
      edge[b].push_back(a);
      hasParent[a] = true;
      a--;b--;
      cond.push_back(make_pair(a,b));
      loopedge[b].push_back(a);
    }
    n++;
    REP(i,1,n){
      if (!hasParent[i])edge[0].push_back(i);
    }
    //cout <<"DEBUGED ANSWER IS " << bf(n-1,cond,s-1,t) << endl;//debug
    //solver
    if (hasLoop(n)){cout << 0 << endl;continue;}
    cout << solve(n,s,t) << endl;
  }
  return 0;
}
accuracy: 1
time_ms: 60
memory_kb: 49000
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)
typedef long long ll;
const ll mod = 1e9 + 7;
const int N = 2010;

//loop finding begin
vector<int> loopedge[N];
int loopvis[N];
bool loopFindingDfs(int u){
  if (loopvis[u] == 2)return false;
  if (loopvis[u] == 1)return true;
  loopvis[u]=1;
  rep(i,(int)loopedge[u].size()){
    if (loopFindingDfs(loopedge[u][i]))return true;
  }
  loopvis[u]=2;
  return false;
}
bool hasLoop(int n){
  rep(i,n)loopvis[i]=0;
  rep(i,n){
    if (loopvis[i] == 0 && loopFindingDfs(i))return true;
  }
  return false;
}
//loop finding end

/*
  brute force solver
  condition x[first] < x[second]
  x[s] = t
*/
//--------------------------------------------------
int bf(int n,vector<pair<int,int> > &cond,int s,int t){
  int x[n];
  int ret = 0;
  rep(i,n)x[i] = i + 1;
  do{
    if (x[s] != t)continue;
    rep(i,cond.size()){
      if (x[cond[i].first] > x[cond[i].second])goto end;
    }
    ret++;
  end:;
  }while(next_permutation(x,x+n));
  return ret;
}
//--------------------------------------------------

ll comb[N][N];
void precalc(){
  comb[0][0] = 1;
  REP(i,1,N){
    comb[i][0] = comb[i][i] = 1;
    REP(j,1,i)comb[i][j] = (comb[i-1][j] + comb[i-1][j-1]) % mod;
  }
}

//solver
vector<int> edge[N];
int child[N];//子ノードの数
int req[N];//X[i]を子ノードとして持つなら、そのノードのインデックスを保持する。
int maxnum[N];//X[i]を子ノードとして持つとき、Xi未満の値を最大どのくらい持っていいのか
int reqnum;//X[i]以下のノードの数。
//子ノードの数を数え上げる。メモ化なし
int countChild(int now){
  int ret = 1;
  rep(i,(int)edge[now].size()){
    ret += countChild(edge[now][i]);
  }
  return child[now] = ret;
}

//X[i]以下のノードの数と、xi以下に遷移するノードの番号を記録しておく。
bool countReq(int now,const int s,bool childOfXs){
  req[now] = -1;
  bool ret = (now == s);
  rep(i,edge[now].size()){
    bool tmp = countReq(edge[now][i],s,childOfXs|(now == s));
    if (tmp)req[now] = i;
    ret |= tmp;
  }
  if (now == s)reqnum = child[now] -1;
  return ret;
}

//xs以下のノードが最大何個まで許容されるかを数える
int countXs(int now,int s){
  if (now == s)return maxnum[now] = child[now] - 1;
  if (req[now] == -1)return child[now];
  int ret = 0;
  maxnum[now] = 0;
  rep(i,edge[now].size()){
    int &next = edge[now][i];
    if (req[now] != i)maxnum[now] += child[next];
    else maxnum[now] += countXs(next,s);
  }
  return maxnum[now];
}

/*
  現在のノード、xs以下のノードの数
  xsを子ノードとして持たない場合はxs=0を代入してしまう
*/
ll dp[N][N];
int solveRec(int now,int xs,int s){
  if (req[now] == -1)xs = 0;
  ll &ret = dp[now][xs];
  if (ret != -1)return ret;
  ret = 1;
  int num = child[now]-1;
  //xsを子ノードとして持つノードから処理していく。
  if (req[now] != -1){
    num--;//tの分を減らす
    ret = 0;
    int &next = edge[now][req[now]];
    REP(i,reqnum,maxnum[next]+1){
      if (xs < i)continue;
      int larger = child[now] - xs -2;//tより大きい
      int konode = child[next]-1;//konode > xi
      konode -= i;
      if (konode > larger)continue;

      ll tmp = solveRec(next,i,s);
      tmp *= comb[xs][i];//xs以下のノードからi個えらぶ。
      tmp %= mod;
      tmp *= comb[larger][konode];//
      ret += tmp;
      ret %= mod;
    }
    num -= child[next];
    num++;//戻しておく。
  }
  rep(i,edge[now].size()){
    if (req[now] == i)continue;//このノードはもう処理したので無視する
    int & next = edge[now][i];
    ll tmp = solveRec(next,0,s);
    tmp *= comb[num][child[next]];
    num -= child[next];
    ret *= tmp;
    ret %= mod;
  }
  return ret;
}

int solve(int n,int s,int t){
  countChild(0);
  countReq(0,s,false);
  countXs(0,s);
  ll ret = solveRec(0,t-1,s);
  return ret;
}


main(){
  precalc();
  int n,c,t,s;
  static bool hasParent[N];
  while(cin>>n>>c>>s>>t && n){
    vector<pair<int,int> > cond;
    rep(i,n){
      loopedge[i].clear();
    }
    rep(i,n+1){
      rep(j,n+1)dp[i][j] = -1;
      hasParent[i] = false;
      edge[i].clear();
      reqnum = 0;
    }
    rep(i,c){
      int a,b;
      cin>>a>>b;
      //擬似的な親としてx0を追加する。こいつは、ルートになっているすべてのノードより大きい必要があるぽよ。
      edge[b].push_back(a);
      hasParent[a] = true;
      a--;b--;
      cond.push_back(make_pair(a,b));
      loopedge[b].push_back(a);
    }
    n++;
    REP(i,1,n){
      if (!hasParent[i])edge[0].push_back(i);
    }
    //cout <<"DEBUGED ANSWER IS " << bf(n-1,cond,s-1,t) << endl;//debug
    //solver
    if (hasLoop(n)){cout << 0 << endl;continue;}
    cout << solve(n,s,t) << endl;
  }
  return 0;
}
accuracy: 0.5384615384615384
time_ms: 50
memory_kb: 49000
final_rank: 6

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)
typedef long long ll;
const ll mod = 1000000007;
const int N = 2010;

//loop finding begin
vector<int> loopedge[N];
int loopvis[N];
bool loopFindingDfs(int u){
  if (loopvis[u] == 2)return false;
  if (loopvis[u] == 1)return true;
  loopvis[u]=1;
  rep(i,(int)loopedge[u].size()){
    if (loopFindingDfs(loopedge[u][i]))return true;
  }
  loopvis[u]=2;
  return false;
}
bool hasLoop(int n){
  rep(i,n)loopvis[i]=0;
  rep(i,n){
    if (loopvis[i] == 0 && loopFindingDfs(i))return true;
  }
  return false;
}
//loop finding end

/*
  brute force solver
  condition x[first] < x[second]
  x[s] = t
*/
//--------------------------------------------------
int bf(int n,vector<pair<int,int> > &cond,int s,int t){
  int x[n];
  int ret = 0;
  rep(i,n)x[i] = i + 1;
  do{
    if (x[s] != t)continue;
    rep(i,cond.size()){
      if (x[cond[i].first] > x[cond[i].second])goto end;
    }
    ret++;
  end:;
  }while(next_permutation(x,x+n));
  return ret;
}
//--------------------------------------------------

ll comb[N][N];
void precalc(){
  comb[0][0] = 1;
  REP(i,1,N){
    comb[i][0] = comb[i][i] = 1;
    REP(j,1,i)comb[i][j] = (comb[i-1][j] + comb[i-1][j-1]) % mod;
  }
}

//solver
vector<int> edge[N];
int child[N];//子ノードの数
int req[N];//X[i]を子ノードとして持つなら、そのノードのインデックスを保持する。
int maxnum[N];//X[i]を子ノードとして持つとき、Xi未満の値を最大どのくらい持っていいのか
int reqnum;//X[i]以下のノードの数。
//子ノードの数を数え上げる。メモ化なし
int countChild(int now){
  int ret = 1;
  rep(i,(int)edge[now].size()){
    ret += countChild(edge[now][i]);
  }
  return child[now] = ret;
}

//X[i]以下のノードの数と、xi以下に遷移するノードの番号を記録しておく。
bool countReq(int now,const int s,bool childOfXs){
  req[now] = -1;
  bool ret = (now == s);
  rep(i,edge[now].size()){
    bool tmp = countReq(edge[now][i],s,childOfXs|(now == s));
    if (tmp)req[now] = i;
    ret |= tmp;
  }
  if (now == s)reqnum = child[now] -1;
  return ret;
}

//xs以下のノードが最大何個まで許容されるかを数える
int countXs(int now,int s){
  if (now == s)return maxnum[now] = child[now] - 1;
  if (req[now] == -1)return child[now];
  int ret = 0;
  maxnum[now] = 0;
  rep(i,edge[now].size()){
    int &next = edge[now][i];
    if (req[now] != i)maxnum[now] += child[next];
    else maxnum[now] += countXs(next,s);
  }
  return maxnum[now];
}

/*
  現在のノード、xs以下のノードの数
  xsを子ノードとして持たない場合はxs=0を代入してしまう
*/
ll dp[N][N];
int solveRec(int now,int xs,int s){
  if (req[now] == -1)xs = 0;
  ll &ret = dp[now][xs];
  if (ret != -1)return ret;
  ret = 1;
  int num = child[now]-1;
  //xsを子ノードとして持つノードから処理していく。
  if (req[now] != -1){
    num--;//tの分を減らす
    ret = 0;
    int &next = edge[now][req[now]];
    REP(i,reqnum,maxnum[next]+1){
      if (xs < i)continue;
      int larger = child[now] - xs -2;//tより大きい
      int konode = child[next]-1;//konode > xi
      konode -= i;
      if (konode > larger)continue;

      ll tmp = solveRec(next,i,s);
      tmp *= comb[xs][i];//xs以下のノードからi個えらぶ。
      tmp *= comb[larger][konode];//
      ret += tmp;
      ret %= mod;
    }
    num -= child[next];
    num++;//戻しておく。
  }
  rep(i,edge[now].size()){
    if (req[now] == i)continue;//このノードはもう処理したので無視する
    int & next = edge[now][i];
    ll tmp = solveRec(next,0,s);
    tmp *= comb[num][child[next]];
    num -= child[next];
    ret *= tmp;
    ret %= mod;
  }
  return ret;
}

int solve(int n,int s,int t){
  countChild(0);
  countReq(0,s,false);
  countXs(0,s);
  ll ret = solveRec(0,t-1,s);
  return ret;
}


main(){
  precalc();
  int n,c,t,s;
  static bool hasParent[N];
  while(cin>>n>>c>>s>>t && n){
    vector<pair<int,int> > cond;
    rep(i,n){
      loopedge[i].clear();
    }
    rep(i,n+1){
      rep(j,n+1)dp[i][j] = -1;
      hasParent[i] = false;
      edge[i].clear();
      reqnum = 0;
    }
    rep(i,c){
      int a,b;
      cin>>a>>b;
      //擬似的な親としてx0を追加する。こいつは、ルートになっているすべてのノードより大きい必要があるぽよ。
      edge[b].push_back(a);
      hasParent[a] = true;
      a--;b--;
      cond.push_back(make_pair(a,b));
      loopedge[b].push_back(a);
    }
    n++;
    REP(i,1,n){
      if (!hasParent[i])edge[0].push_back(i);
    }
    //cout <<"DEBUGED ANSWER IS " << bf(n-1,cond,s-1,t) << endl;//debug
    //solver
    if (hasLoop(n)){cout << 0 << endl;continue;}
    cout << solve(n,s,t) << endl;
  }
  return 0;
}
accuracy: 0.5384615384615384
time_ms: 50
memory_kb: 51000
final_rank: 7

code_snippet: #include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <math.h>
#include <assert.h>
#include <vector>
#include <queue>
#include <string>
#include <map>
#include <set>

using namespace std;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
static const double EPS = 1e-9;
static const double PI = acos(-1.0);

#define REP(i, n) for (int i = 0; i < (int)(n); i++)
#define FOR(i, s, n) for (int i = (s); i < (int)(n); i++)
#define FOREQ(i, s, n) for (int i = (s); i <= (int)(n); i++)
#define FORIT(it, c) for (__typeof((c).begin())it = (c).begin(); it != (c).end(); it++)
#define MEMSET(v, h) memset((v), h, sizeof(v))

const ll MOD = 1e+9 + 7;
ll combi[2020][2020];
vector<int> g[2020];
int parent[2020];
int memo[2020][2020];
int cnt[2020];
int cnt2[2020];
int sum[2020];
int n, c, s, t;

void dfs(int node) {
  ll c = 1;
  sum[node] = 1;
  FORIT(it, g[node]) {
    dfs(*it);
    sum[node] += sum[*it];
  }
  ll rest = sum[node] - 1;
  FORIT(it, g[node]) {
    c = c * cnt[*it] % MOD * combi[rest][sum[*it]] % MOD;
    rest -= sum[*it];
  }
  cnt[node] = c;
}

ll Cnt(int node, int left, int child) {
  int rest = n - left;
  if (cnt2[node] == -1) {
    ll ret = 1;
    int r = sum[node] - 1;
    if (node != child) { r -= sum[child]; }
    FORIT(it, g[node]) {
      if (*it == child) { continue; }
      ret = ret * cnt[*it] % MOD * combi[r][sum[*it]] % MOD;
      r -= sum[*it];
    }
    cnt2[node] = ret;
  }
  rest--;
  int r = sum[node] - 1;
  if (node != child) {
    rest -= sum[child];
    r -= sum[child];
  }
  if (rest < 0) { return 0; }
  return cnt2[node] * combi[rest][r] % MOD;
}

ll calc(int node, int left, int child) {
  if (left < 0) { return 0; }
  if (memo[node][left] != -1) { return memo[node][left]; }
  ll ret = Cnt(node, left, child);
  if (node != 0) {
    ret = (ret * calc(parent[node], left - 1, node)) % MOD;
  }
  if (node != child) {
    ret = (ret + calc(node, left - 1, child)) % MOD;
  }
  return memo[node][left] = ret;
}

int main() {
  MEMSET(combi, 0);
  combi[0][0] = 1;
  REP(i, 2010) REP(j, 2010) {
    combi[i + 1][j] = (combi[i + 1][j] + combi[i][j]) % MOD;
    combi[i + 1][j + 1] = (combi[i + 1][j + 1] + combi[i][j]) % MOD;
  }
  while (scanf("%d %d %d %d", &n, &c, &s, &t) > 0) {
    n++;
    t = n - t;
    MEMSET(parent, 0);
    MEMSET(memo, -1);
    MEMSET(cnt, -1);
    MEMSET(cnt2, -1);
    MEMSET(sum, 0);
    REP(i, 2020) { g[i].clear(); }
    REP(i, c) {
      int from, to;
      scanf("%d %d", &to, &from);
      g[from].push_back(to);
      parent[to] = from;
    }
    FOR(i, 1, n) {
      if (parent[i] == 0) { g[0].push_back(i); }
    }
    dfs(0);
    ll ans = 0;
    if (sum[0] == n) {
      ans = calc(s, t, s);
    }
    printf("%lld\n", ans);
  }
}
accuracy: 1
time_ms: 260
memory_kb: 0
final_rank: 4

code_snippet: #include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <math.h>
#include <assert.h>
#include <vector>
#include <queue>
#include <string>
#include <map>
#include <set>

using namespace std;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
static const double EPS = 1e-9;
static const double PI = acos(-1.0);

#define REP(i, n) for (int i = 0; i < (int)(n); i++)
#define FOR(i, s, n) for (int i = (s); i < (int)(n); i++)
#define FOREQ(i, s, n) for (int i = (s); i <= (int)(n); i++)
#define FORIT(it, c) for (__typeof((c).begin())it = (c).begin(); it != (c).end(); it++)
#define MEMSET(v, h) memset((v), h, sizeof(v))

const ll MOD = 1e+9 + 7;
ll combi[2020][2020];
vector<int> g[2020];
int parent[2020];
int memo[2020][2020];
int cnt[2020];
int cnt2[2020];
int sum[2020];
int n, c, s, t;

void dfs(int node) {
  ll c = 1;
  sum[node] = 1;
  FORIT(it, g[node]) {
    dfs(*it);
    sum[node] += sum[*it];
  }
  ll rest = sum[node] - 1;
  FORIT(it, g[node]) {
    c = c * cnt[*it] % MOD * combi[rest][sum[*it]] % MOD;
    rest -= sum[*it];
  }
  cnt[node] = c;
}

ll Cnt(int node, int left, int child) {
  int rest = n - left;
  if (rest < sum[node]) { return 0; }
  if (cnt2[node] != -1) { return cnt2[node]; }
  ll ret = 1;
  int r = sum[node] - 1;
  if (node != child) { r -= sum[child]; }
  FORIT(it, g[node]) {
    if (*it == child) { continue; }
    ret = ret * cnt[*it] % MOD * combi[r][sum[*it]] % MOD;
    r -= sum[*it];
  }
  return cnt2[node] = ret;
}

ll calc(int node, int left, int child) {
  if (left < 0) { return 0; }
  if (memo[node][left] != -1) { return memo[node][left]; }
  ll ret = Cnt(node, left, child);
  if (node != 0) {
    ret = (ret * calc(parent[node], left - 1, node)) % MOD;
  }
  if (node != child) {
    ret = (ret + calc(node, left - 1, child)) % MOD;
  }
  return memo[node][left] = ret;
}

int main() {
  MEMSET(combi, 0);
  combi[0][0] = 1;
  REP(i, 2010) REP(j, 2010) {
    combi[i + 1][j] = (combi[i + 1][j] + combi[i][j]) % MOD;
    combi[i + 1][j + 1] = (combi[i + 1][j + 1] + combi[i][j]) % MOD;
  }
  while (scanf("%d %d %d %d", &n, &c, &s, &t) > 0) {
    n++;
    t = n - t;
    MEMSET(parent, 0);
    MEMSET(memo, -1);
    MEMSET(cnt, -1);
    MEMSET(cnt2, -1);
    MEMSET(sum, 0);
    REP(i, 2020) { g[i].clear(); }
    REP(i, c) {
      int from, to;
      scanf("%d %d", &to, &from);
      g[from].push_back(to);
      parent[to] = from;
    }
    FOR(i, 1, n) {
      if (parent[i] == 0) { g[0].push_back(i); }
    }
    dfs(0);
    ll ans = 0;
    if (sum[0] == n) {
      ans = calc(s, t, s);
    }
    printf("%lld\n", ans);
  }
}
accuracy: 0.1282051282051282
time_ms: 150
memory_kb: 0
final_rank: 8

code_snippet: #include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <math.h>
#include <assert.h>
#include <vector>
#include <queue>
#include <string>
#include <map>
#include <set>

using namespace std;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
static const double EPS = 1e-9;
static const double PI = acos(-1.0);

#define REP(i, n) for (int i = 0; i < (int)(n); i++)
#define FOR(i, s, n) for (int i = (s); i < (int)(n); i++)
#define FOREQ(i, s, n) for (int i = (s); i <= (int)(n); i++)
#define FORIT(it, c) for (__typeof((c).begin())it = (c).begin(); it != (c).end(); it++)
#define MEMSET(v, h) memset((v), h, sizeof(v))

const ll MOD = 1e+9 + 7;
ll combi[2020][2020];
vector<int> g[2020];
int parent[2020];
int memo[2020][2020];
int cnt[2020];
int cnt2[2020];
int sum[2020];
int n, c, s, t;

void dfs(int node) {
  ll c = 1;
  sum[node] = 1;
  FORIT(it, g[node]) {
    dfs(*it);
    sum[node] += sum[*it];
  }
  ll rest = sum[node] - 1;
  FORIT(it, g[node]) {
    c = c * cnt[*it] % MOD * combi[rest][sum[*it]] % MOD;
    rest -= sum[*it];
  }
  cnt[node] = c;
}

ll Cnt(int node, int left, int child) {
  int rest = n - left;
  if (rest < sum[node]) { return 0; }
  if (cnt2[node] != -1) { return cnt2[node]; }
  ll ret = 1;
  FORIT(it, g[node]) {
    if (*it == child) { continue; }
    ret = (ret * cnt[*it]) % MOD;
  }
  return cnt2[node] = ret;
}

ll calc(int node, int left, int child) {
  if (left < 0) { return 0; }
  if (memo[node][left] != -1) { return memo[node][left]; }
  ll ret = Cnt(node, left, child);
  if (node != 0) {
    ret = (ret * calc(parent[node], left - 1, node)) % MOD;
  }
  if (node != child) {
    ret = (ret + calc(node, left - 1, child)) % MOD;
  }
  return memo[node][left] = ret;
}

int main() {
  MEMSET(combi, 0);
  combi[0][0] = 1;
  REP(i, 2010) REP(j, 2010) {
    combi[i + 1][j] = (combi[i + 1][j] + combi[i][j]) % MOD;
    combi[i + 1][j + 1] = (combi[i + 1][j + 1] + combi[i][j]) % MOD;
  }
  while (scanf("%d %d %d %d", &n, &c, &s, &t) > 0) {
    n++;
    t = n - t;
    MEMSET(parent, 0);
    MEMSET(memo, -1);
    MEMSET(cnt, -1);
    MEMSET(cnt2, -1);
    MEMSET(sum, 0);
    REP(i, 2020) { g[i].clear(); }
    REP(i, c) {
      int from, to;
      scanf("%d %d", &to, &from);
      g[from].push_back(to);
      parent[to] = from;
    }
    FOR(i, 1, n) {
      if (parent[i] == 0) { g[0].push_back(i); }
    }
    dfs(0);
    ll ans = 0;
    if (sum[0] == n) {
      ans = calc(s, t, s);
    }
    printf("%lld\n", ans);
  }
}
accuracy: 0.10256410256410256
time_ms: 120
memory_kb: 0
final_rank: 10

code_snippet: #include<iostream>
#include<sstream>
#include<vector>
#include<algorithm>
#include<set>
#include<map>
#include<queue>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cassert>
using namespace std;

#define rep(i,n) for(int i=0;i<(int)n;i++)
#define fr(i,c) for(__typeof(c.begin()) i=c.begin();i!=c.end();i++)
#define pb push_back
#define mp make_pair
#define all(c) c.begin(),c.end()
#define dbg(x) cerr<<#x<<" = "<<(x)<<endl

typedef vector<int> vi;
typedef pair<int,int> pi;
typedef long long ll;
const int inf=(int)1e9;
const double EPS=1e-9, INF=1e12;

const int mod=(int)1e9+7;
int n,c,s,t;
ll C[2002][2002];
int m,in[2002];
vector<vi> e;

bool v[2002];
void rec(int c){
	v[c]=1;
	rep(i,e[c].size())if(!v[e[c][i]])rec(e[c][i]);
}
bool hasloop(){
	rep(i,n)if(in[i]==0&&!v[i])rec(i);
	rep(i,n)if(!v[i])return 1;
	return 0;
}

int cld[2002];
int reccld(int c){
	if(cld[c]>=0)return cld[c];
	cld[c]=1;
	rep(i,e[c].size())cld[c]+=reccld(e[c][i]);
	return cld[c];
}
ll T[2002];
ll recT(int c){
	ll &res=T[c];
	if(res>=0)return res;
	res=1;
	int n=cld[c]-1;
	rep(i,e[c].size()){
		res=res*recT(e[c][i])%mod;
		res=res*C[n][cld[e[c][i]]]%mod;
		n-=cld[e[c][i]];
	}
	return res;
}
ll dp[2002][2002],sum[2002][2002];

int main(){
	rep(i,2002)rep(j,i+1)C[i][j]=i==0||i==j?1ll:(C[i-1][j-1]+C[i-1][j])%mod;
	
	cin>>n>>c>>s>>t;
	e.resize(++n);
	rep(i,c){
		int a,b; cin>>a>>b;
		e[b].pb(a);
		in[a]++;
	}
	if(hasloop()){
		cout<<0<<endl; return 0;
	}
	for(int i=1;i<n;i++)if(in[i]==0)e[0].pb(i);
	t=n-t;
	
	static int prev[2002];
	rep(i,n)prev[i]=-1;
	queue<int> q; q.push(0);
	while(!q.empty()){
		int c=q.front(); q.pop();
		if(c==s)break;
		rep(i,e[c].size())q.push(e[c][i]), prev[e[c][i]]=c;
	}
	vi path;
	for(int c=s;c>=0;c=prev[c])path.pb(c);
	reverse(all(path));
	m=path.size();
	path.pb(n+1); T[n+1]=1;
	
	rep(i,n)cld[i]=T[i]=-1;
	rep(i,n)if(cld[i]<0)reccld(i);
	rep(i,n)if(T[i]<0)recT(i);
	
	rep(i,m){
		ll mul=1; int x=cld[path[i]]-cld[path[i+1]]-1;
		rep(j,e[path[i]].size())if(e[path[i]][j]!=path[i+1]){
			mul=mul*T[e[path[i]][j]]%mod*C[x][cld[e[path[i]][j]]]%mod;
			x-=cld[e[path[i]][j]];
		}
		rep(j,n+1)if(j>=i&&n-cld[path[i+1]]-1-j>=0){
			ll tmp=i&&j?sum[i-1][j-1]:1;
			tmp=tmp*C[n-cld[path[i+1]]-1-j][cld[path[i]]-cld[path[i+1]]-1]%mod;
			tmp=tmp*mul%mod;
			dp[i][j]=tmp;
			sum[i][j]=((j?sum[i][j-1]:0)+dp[i][j])%mod;
		}
	}
	cout<<dp[m-1][t]<<endl;
	
	return 0;
}
accuracy: 1
time_ms: 60
memory_kb: 35000
final_rank: 1

code_snippet: #include<iostream>
#include<sstream>
#include<vector>
#include<algorithm>
#include<set>
#include<map>
#include<queue>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cassert>
using namespace std;

#define rep(i,n) for(int i=0;i<(int)n;i++)
#define fr(i,c) for(__typeof(c.begin()) i=c.begin();i!=c.end();i++)
#define pb push_back
#define mp make_pair
#define all(c) c.begin(),c.end()
#define dbg(x) cerr<<#x<<" = "<<(x)<<endl

typedef vector<int> vi;
typedef pair<int,int> pi;
typedef long long ll;
const int inf=(int)1e9;
const double EPS=1e-9, INF=1e12;

const int mod=(int)1e9+7;
int n,c,s,t;
ll C[2002][2002];
int m,in[2002];
vector<vi> e;

bool v[2002];
void rec(int c){
	v[c]=1;
	rep(i,e[c].size())if(!v[e[c][i]])rec(e[c][i]);
}
bool hasloop(){
	rep(i,n)if(in[i]==0&&!v[i])rec(i);
	rep(i,n)if(!v[i])return 1;
	return 0;
}

int cld[2002];
int reccld(int c){
	if(cld[c]>=0)return cld[c];
	cld[c]=1;
	rep(i,e[c].size())cld[c]+=reccld(e[c][i]);
	return cld[c];
}
ll T[2002];
ll recT(int c){
	ll &res=T[c];
	if(res>=0)return res;
	res=1;
	int n=cld[c]-1;
	rep(i,e[c].size()){
		res=res*recT(e[c][i])%mod;
		res=res*C[n][cld[e[c][i]]]%mod;
		n-=cld[e[c][i]];
	}
	return res;
}
ll dp[2002][2002],sum[2002][2002];

int main(){
	rep(i,2002)rep(j,i+1)C[i][j]=i==0||i==j?1ll:(C[i-1][j-1]+C[i-1][j])%mod;
	
	cin>>n>>c>>s>>t;
	e.resize(++n);
	rep(i,c){
		int a,b; cin>>a>>b;
		e[b].pb(a);
		in[a]++;
	}
	if(hasloop()){
		cout<<0<<endl; return 0;
	}
	for(int i=1;i<n;i++)if(in[i]==0)e[0].pb(i);
	t=n-t;
	
	static int prev[2001];
	rep(i,n)prev[i]=-1;
	queue<int> q; q.push(0);
	while(!q.empty()){
		int c=q.front(); q.pop();
		if(c==s)break;
		rep(i,e[c].size())q.push(e[c][i]), prev[e[c][i]]=c;
	}
	vi path;
	for(int c=s;c>=0;c=prev[c])path.pb(c);
	reverse(all(path));
	m=path.size();
	path.pb(n+1); T[n+1]=1;
	
	rep(i,n)cld[i]=T[i]=-1;
	rep(i,n)if(cld[i]<0)reccld(i);
	rep(i,n)if(T[i]<0)recT(i);
	
	rep(i,m){
		ll mul=1; int x=cld[path[i]]-cld[path[i+1]]-1;
		rep(j,e[path[i]].size())if(e[path[i]][j]!=path[i+1]){
			mul=mul*T[e[path[i]][j]]%mod*C[x][cld[e[path[i]][j]]]%mod;
			x-=cld[e[path[i]][j]];
		}
		rep(j,n+1)if(j>=i&&n-cld[path[i+1]]-1-j>=0){
			ll tmp=i&&j?sum[i-1][j-1]:1;
			tmp=tmp*C[n-cld[path[i+1]]-1-j][cld[path[i]]-cld[path[i+1]]-1]%mod;
			tmp=tmp*mul%mod;
			dp[i][j]=tmp;
			sum[i][j]=(j?sum[i][j-1]:0)+dp[i][j];
			
		}
	}
	cout<<dp[m-1][t]<<endl;
	
	return 0;
}
accuracy: 0.1282051282051282
time_ms: 50
memory_kb: 30000
final_rank: 9