AOJ - POLY

세로를 보지말고 가로로 정사각형들을 쌓는다고 하자.

$dp[ \text{remain} ][ \text{last\_len} ]=$ 현재 남은 블럭이 remain 개이고 바로 위 블럭이 쌓아진 칸의 길이가 last_len 일 때, 계속 쌓았을 때 정답의 수

문제에서 설명하는 도형을 만들기 위해 정사각형은 항상 1자로 붙여서 가로로 쌓아야 한다는 것을 알 수 있고, 다음에 쌓을 개수가 $K$ 라면 $K+\text{last\_len}-1$ 개의 경우의 수를 쌓을 수 있다.

따라서

$dp[\text{remain}][\text{last\_len}]= \begin{cases} \displaystyle\sum_{k=1}^{\text{remain}}\left( (K+\text{last\_len}-1) \cdot dp[ \text{remain}-K][K] \right)\\ 1~(\text{remain}=0) \end{cases}$

const ll mod = 1e7;  
inline ll md(ll x) { return md(mod, x); }  
int dp[222][222];  
  
int fn(int remain, int last_len) {  
   if (remain == 0) return 1;  
   int &ret = dp[remain][last_len];  
   if (~ret) return ret;  
   ret = 0;  
   for (int nxt_len = 1; nxt_len <= remain; nxt_len++) {  
      ret = md(ret + fn(remain - nxt_len, nxt_len) * (nxt_len + last_len - 1));  
   }  
   return ret;  
}  
  
void solve() {  
   int n;  
   cin >> n;  
   memset(dp, -1, sizeof dp);  
   int ans = 0;  
   for (int len = 1; len <= n; len++) {  
      ans = md(ans + fn(n - len, len));  
   }  
   cout << ans << endl;  
}

Comments