其他分享
首页 > 其他分享> > Solution HTR003D

Solution HTR003D

作者:互联网

50 分:

暴力枚举即可

100 分:

设输入的序列为 \(a_i\)。容易发现,如果我们按原序列从左往右扫,扫到第 \(i\) 个位置时,我们要考虑的是这一个位置要填什么以及 \(a_i\) 要填到哪个位置上。

并且一共只有 5 种情况:

那么我们记 \(f_{i,j,p}\) 表示现在填完第 \(i\) 个数,比 \(i\) 小(包括 \(i\))的有 \(j\) 个没填,并且算出来的价值为 \(p\) 的方案数。假设我们现在考虑 \(i+1\) 位填的数,分别考虑以上的五种情况。不过这里要注意的一点就是当这个位置填的数比它小时,是无法确定究竟是 \(j\) 个当中的哪一个,因此这一部分的价值需要在之前填上 \(j\) 这一位的时候就统计在答案中。

为了方便表述,借助标程的代码段进行解释(一些边界判断和取模略去):

f[i+1][j][p+a[i+1]] += f[i][j][p];//第 i+1 位填 a[i+1],不会产生新的未填项,并且产生新贡献为 a[i+1]
f[i+1][j-1][p] += f[i][j][p]*j*j;//第 i+1 位填比 a[i+1] 小的数并且 a[i+1] 填到比 i+1 小的位置上。减少一个未填项,产生新贡献为 0(这些贡献之前之前已经计算)
f[i+1][j][p+a[i+1]] += f[i][j][p]*j;//第 i+1 位填比 a[i+1] 小的数并且 a[i+1] 填到比 i+1 大的位置上。未填项数目不改变,产生新贡献为 a[i+1](贡献来自 a[i+1] 填到的那位)
f[i+1][j+1][p+2*a[i+1]] += f[i][j][p];//第 i+1 位填比 a[i+1] 大的数并且 a[i+1] 填到比 i+1 大的位置上。未填项数目 +1,产生新贡献为 2*a[i+1](贡献来自 i+1 位和 a[i+1] 填到的那位)
f[i+1][j][p+a[i+1]] += f[i][j][p]*j;//第 i+1 位填比 a[i+1] 大的数并且 a[i+1] 填到比 i+1 小的位置上。未填项数目不改变,产生新贡献为 a[i+1](贡献来自 i+1 位)

Code

#include <bits/stdc++.h>
using namespace std;
const int N = 2500 + 5, mod = 1e9 + 9;

int n, k, f[51][51][N], a[51];

int main() {
    scanf("%d%d", &n, &k);

    for (int i = 1; i <= n; i++)
        scanf("%d", &a[i]);

    f[0][0][0] = 1;

    for (int i = 0; i < n; i++)
        for (int j = 0; j <= i; j++)
            for (int p = 0; p <= k; p++)
                if (f[i][j][p]) {
                    if (p + a[i + 1] <= k)
                        (f[i + 1][j][p + a[i + 1]] += f[i][j][p]) %= mod;

                    if (j)
                        (f[i + 1][j - 1][p] += 1ll * f[i][j][p] * j * j % mod) %= mod;

                    if (j && p + a[i + 1] <= k)
                        (f[i + 1][j][p + a[i + 1]] += 1ll * f[i][j][p] * j % mod) %= mod;

                    if (p + 2 * a[i + 1] <= k)
                        (f[i + 1][j + 1][p + 2 * a[i + 1]] += f[i][j][p]) %= mod;

                    if (j && p + a[i + 1] <= k)
                        (f[i + 1][j][p + a[i + 1]] += 1ll * f[i][j][p] * j % mod) %= mod;
                }

    printf("%d\n", f[n][0][k]);
    return 0;
}

标签:HTR003D,数填到,未填项,位置,Solution,贡献,填到,并且
来源: https://www.cnblogs.com/xlqs23/p/16573517.html