题解 CF182E 【Wooden Fence】
pythoner713 · · 题解
给定
现在需要从中选一些木板,拼成长度总和为
建出的栅栏要求相邻两块木板:
- 种类不能一样
- 前者的长度需等于后者的宽度
请你求出有多少种建栅栏的方案数。答案对
这题可以用 DP 解决。记
对于每一种木板,若其不是正方形,则可以将其拆为长宽分别为
枚举上一块木板的种类
#include<bits/stdc++.h>
#define p 1000000007
#define nb 210
using namespace std;
int ans, n, l, cnt, a[nb], b[nb], c[nb], f[3010][nb];
// f[i][j] = 当前长度为 i, 最后一块木板为 j 的总方案数
// f[i][j] += f[i - a[j]][k] (a[j] = b[k], c[j] != c[k])
int main(){
cin >> n >> l;
for(int i = 1; i <= n; i++){
c[++cnt] = i;
cin >> a[cnt] >> b[cnt];
if(a[cnt] != b[cnt]){
c[++cnt] = i;
a[cnt] = b[cnt - 1];
b[cnt] = a[cnt - 1];
// 如果不是正方形,将其拆成两种木板
// 但原来的木板种类仍为 i
}
}
for(int i = 1; i <= l; i++){
for(int j = 1; j <= cnt; j++){
for(int k = 0; k <= cnt; k++){
if(c[j] == c[k]) continue; // 若种类相同则跳过
if(!k && a[j] == i) f[i][j]++; // k = 0 代表当前已是第一块木板
else if(a[j] == b[k] && i > a[j]){
// 根据限制条件二, a[j] = b[k]
f[i][j] = (f[i][j] + f[i - a[j]][k]) % p;
}
}
}
}
for(int i = 1; i <= cnt; i++) ans = (ans + f[l][i]) % p;
cout << ans;
return 0;
}