【题意】:
【题解】:设dp[i][j][k]表示当前长度为i,最大值为j,已经更新了k次的合理方案数。
转移方程 dp[i][j][k] = dp[i-1][j][k] * j + ∑dp[i-1][1...j-1][k]
由于状态数高达100 * 300 * 100,用上面的转移方程显然会TLE。观测转移方程,我们很容易想到用部分和优化,这样就可以把转移降为O(1)。
最后 ans = ∑dp[n][i...m][p].
【代码】:
1 #include "iostream"
2 #include "cstdio"
3 #include "cstring"
4 using namespace std;
5 #define ll long long
6 const ll MOD = 1000000007LL;
7 ll dp[110][310][110];
8 int n, m, p;
9 void solve() {
10 for(int i = 0; i <= n; i++)
11 for(int j = 0; j <= m; j++)
12 for(int k = 0; k <= p; k++)
13 dp[i][j][k] = 0;
14 for(int i = 1; i <= m; i++) dp[1][i][0] = 1;
15 for(int i = 2; i <= n; i++) {
16 for(int k = 0; k <= p && k < i; k++) {
17 ll sum = 0;
18 for(int j = 1; j <= m; j++) {
19 dp[i][j][k] += dp[i-1][j][k] * j;
20 if(k) dp[i][j][k] += sum;
21 while(dp[i][j][k] >= MOD) dp[i][j][k] -= MOD;
22 sum += dp[i-1][j][k-1];
23 }
24 }
25 }
26 ll ans = 0;
27 for(int i = 1; i <= m; i++) ans += dp[n][i][p];
28 printf("%lld\n", ans % MOD);
29 }
30
31 int main() {
32 int T;
33 scanf("%d", &T);
34 while(T--) {
35 scanf("%d%d%d", &n, &m, &p);
36 solve();
37 }
38 return 0;
39 }
40