ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Solution HTR003D

2022-08-10 18:30:08  阅读:130  来源: 互联网

标签:HTR003D 数填到 未填项 位置 Solution 贡献 填到 并且


50 分:

暴力枚举即可

100 分:

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

并且一共只有 5 种情况:

  • \(a_i\) 填到 \(i\) 上;
  • 拿一个比 \(a_i\) 小的数填到 \(i\) 上并且 \(a_i\) 填到比 \(i\) 小的位置上;
  • 拿一个比 \(a_i\) 小的数填到 \(i\) 上并且 \(a_i\) 填到比 \(i\) 大的位置上;
  • 拿一个比 \(a_i\) 大的数填到 \(i\) 上并且 \(a_i\) 填到比 \(i\) 大的位置上;
  • 拿一个比 \(a_i\) 大的数填到 \(i\) 上并且 \(a_i\) 填到比 \(i\) 小的位置上

那么我们记 \(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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有