haraduka's diary

やる気が欲しい

CodeFestival2015本戦 G問題 スタンプラリー

むーーーこれは難しい。
Euler Tourという考え方で、行きがけ順の配列で木を表すというもの。
まぁそれをもとに今度は木を構成しなおすという話だが、解説スライドでは木と森という考え方を使っている。
実際にはまぁ仮想的な根を考えることで木の考え方だけで解ける。
今回は解説にあった方法を愚直に実装してみた。
この考え方天才的だ。最高。

constexpr ll mod = (ll)1e9+7;
constexpr int MAXN = 256;
int N;
int C[MAXN];
ll dp_tree[MAXN+1][MAXN+1];
ll dp_forest[MAXN+1][MAXN+1];

ll dfs_forest(int l, int r);

ll dfs_tree(int l, int r) //[l, r)でいくつ木が作れるか?
{
    if(r-l == 1) return 1; //要素がひとつになったら一つの木
    if(dp_tree[l][r] > 0) return dp_tree[l][r];
    ll ans = dfs_forest(l+1, r); //[l+1, r)の森にlを根としてつけたしたら木
    return dp_tree[l][r] = ans;
}

ll dfs_forest(int l, int r) //[l, r)でいくつ森が作れるか?
{
    if(r-l == 1) return 1; //要素がひとつになったら一つの森
    if(dp_forest[l][r] > 0) return dp_forest[l][r];
    ll ans = dfs_tree(l, r); //木は森
    for(int i=l+1; i<r; i++){ //[l, i)の木に[i, r)の森をつけたしたら森
        if(C[l] < C[i]){
            ans += dfs_tree(l, i)*dfs_forest(i, r);
            ans %= mod;
        }
    }
    return dp_forest[l][r] = ans;
}

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

    cin >> N;
    rep(i, N) cin >> C[i], C[i]--;
    if(C[0] != 0){
        cout << 0 << endl;
        return 0;
    }

    cout << dfs_tree(0, N) << endl;
}