AOJ2439 Hakone

箱根駅伝。問題概要は略。
解法が面白かったのでメモ

dp[i][j] : 現在i位まで見てj個unmatchedな場合の数
として、
i番目が-ならそのまま,
Dならi番目をそれまでの空いているところに入れるのでj通り,
またi番目にそれまでのを入れる.... dp[i+1][j-1] += dp[i][j] * j * j
スルー.... dp[i+1][j] += dp[i][j] * j

Uなら
i番目にそれまでのを入れる... dp[i+1][j] += dp[i][j] * j
スルー... dp[i+1][j+1] += dp[i][j]

として更新するとO(n^2)で解ける

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

typedef long long ll;
#define rep(i,n)  for(int i = 0; i < (int)n; ++i)

const int MOD = 1000000007;

int n;
int dp[210][210];

inline void md(int &x, int y){ x += y; if(x >= MOD) x -= MOD; }

int main(){
    dp[0][0] = 1;
    scanf("%d", &n);
    rep(i, n){
	char c[3]; scanf("%s", c);
	if(c[0] == '-') for(int j = 0; j <= i + 1; ++j) dp[i+1][j] = dp[i][j];
	else if(c[0] == 'D'){
	    for(int j = 1; j <= i + 1; ++j){
		md(dp[i+1][j-1], (ll)dp[i][j] * j * j % MOD);
		md(dp[i+1][j], (ll)dp[i][j] * j % MOD);
	    }
	}else{
	    for(int j = 0; j <= i; ++j){
		md(dp[i+1][j], (ll)dp[i][j] * j % MOD);
		md(dp[i+1][j+1], dp[i][j]);
	    }
	}
    }
    printf("%d\n", dp[n][0]);
    return 0;
}