Fabricating Sculptures 题解
草草地写一篇题解,废话不多说
暴力
要拼成“^”型,考虑 \(DP\)
令 \(f_{i,j}\) 表示,总共有 \(i\) 个积木,其中底座占了 \(j\) 个积木,也就是说你还有 \(i-j\) 个积木来拼底座的上方。
转移方程:\(f_{i,j} = \sum\limits_{k=1}^{j} f_{i-j,k} (j-k+1)\)
初始化:\(f_{1,1}=1, f_{i,i}=1\),其中 \(i \le m\)
代码如下
#include <iostream>
using namespace std;
const int N = 5010;
int n, m;
int f[N][N];
int main()
{
cin >> m >> n;
f[1][1] = 1;
for (int i = 1; i <= m; i ++ ) f[i][i] = 1;
for (int i = 2; i <= n; i ++ )
{
for (int j = 1; j <= min(i - 1, m); j ++ )
{
for (int k = 1; k <= j; k ++ )
{
f[i][j] += f[i - j][k] * (j - k + 1);
}
}
// if (i <= m) f[i][i] = 1;
}
cout << f[n][m] << endl;
}
然而 \(TLE\) 了。
前缀和优化
令 \(sum1_{i,j} = \sum\limits_{j=1}^m f_{i,j},\ sum2_{i,j} = j\sum\limits_{j=1}^m f_{i,j}\)
那么新的状态转移方程变成了:\(f_{i,j} = (j+1)sum1_{i-j,j} - sum2_{i-j,j}\)
#include <iostream>
using namespace std;
typedef long long LL;
const int N = 5010;
const LL mod = 1e9 + 7;
LL n, m;
LL f[N][N], sum1[N][N], sum2[N][N];
int main()
{
cin >> m >> n;
f[1][1] = 1;
for (int i = 1; i <= m; i ++ ) f[i][i] = 1;
for (LL i = 1; i <= n; i ++ )
sum1[1][i] = sum2[1][i] = 1;
for (LL i = 2; i <= n; i ++ )
{
for (LL j = 1; j <= min(i - 1, m); j ++ )
f[i][j] = ((j + 1) * sum1[i - j][j] - sum2[i - j][j]) % mod;
// if (i <= m) f[i][i] = 1;
for (LL j = 1; j <= m; j ++ )
{
sum1[i][j] = (sum1[i][j - 1] + f[i][j]) % mod;
sum2[i][j] = (sum2[i][j - 1] + f[i][j] * j) % mod;
}
}
cout << f[n][m] << endl;
}