其他分享
首页 > 其他分享> > P7961 [NOIP2021] 数列 题解

P7961 [NOIP2021] 数列 题解

作者:互联网

我好菜啊,动态规划一点不会,一年前的题目,还要想接近 \(2h\) 才会。

考虑 \(a\) 数组顺序并没有影响,于是全部由顺序放置。

然后,最后的方案数通过组合数计算。

因为值域限制很大,于是对进制进行 dp。

设立 \(dp_{i,j,k,p}\) 表示当前讨论到 \(S\) 中第 \(i\) 位,\(a\) 中已经有了 \(j\) 个元素被确定,当前有了 \(k\) 个 \(1\) 存在,\(i - 1\) 位向当前 \(i\) 位进位 \(p\) 个 \(1\)。

考虑刷表法,枚举选了 \(t\) 个 \(i\),于是 \(dp_{i,j,k,p} \rightarrow dp_{i+1,j+t,k + (t + p) \bmod 2,\frac{p + t}{2}}\)。

然后转移的贡献为 \(dp_{i,j,k,p} \times v_i^t \times \binom{n-j}{t}\)。

然后统计答案随便弄弄就完了,真的菜,当时这都不会。

// 德丽莎你好可爱德丽莎你好可爱德丽莎你好可爱德丽莎你好可爱德丽莎你好可爱
// 德丽莎的可爱在于德丽莎很可爱,德丽莎为什么很可爱呢,这是因为德丽莎很可爱!
#include <bits/stdc++.h>
#define int long long
using namespace std;
inline int read() {
  int x = 0, f = 1;  char ch = getchar();
  while( !isdigit(ch) ) { if(ch == '-') f = -1;  ch = getchar();  }
  while( isdigit(ch) ) {  x = (x << 1) + (x << 3) + (ch ^ 48);  ch = getchar();  }
  return x * f;
}
const int mod = 998244353, N = 700;
int n, m, ans, kqwq, v[N], fac[N], ifac[N], dp[N][65][65][65], c[N][N];
int power(int a,int b) { int ans = 1; while (b) { if (b & 1) ans = ans * a % mod; b >>= 1; a = a * a % mod; } return ans; }
int binom(int n,int m) { return c[n][m]; }
signed main () {
  n = read(), m = read(), kqwq = read();
  for (int i = 0; i <= m; i++) v[i] = read(); 
  dp[0][0][0][0] = 1; c[0][0] = 1;
  for (int i = 0; i <= n; i++) {
    c[i][0] = 1; c[i][i] = 1;
    for (int j = 1; j < i; j++) 
      c[i][j] = c[i - 1][j]  + c[i - 1][j - 1], c[i][j] %= mod;
  }
  for (int i = 0; i <= m; i++) {
    for (int j = 0; j <= n; j++) {
      for (int k = 0; k <= kqwq; k++) {
        for (int p = 0; p <= (n / 2); p++) {
          for (int t = 0; t <= n; t++) {
            if (t + j > n) continue;
            dp[i + 1][j + t][k + (p + t) % 2][(p + t) / 2] += dp[i][j][k][p] * binom(n - j, t) % mod * power(v[i], t) % mod;
            dp[i + 1][j + t][k + (p + t) % 2][(p + t) / 2] %= mod; 
            //cout << i << " " << j << " " << k << " " << p << " " << power(v[i], t) <<" " << binom(n - j, t)<< " qwq\n";
            //cout << i + 1 << " " << j + t << " " << (k + (j + t) % 2) << " " << (j + t) / 2 << " " << dp[i + 1][j + t][k +]
          }
        }
      }
    }
  }
  int ans = 0;
  for (int k = 0; k <= kqwq; k++) {
    for (int p = 0; p <= (n / 2); p++) {
      if (k + __builtin_popcount(p) <= kqwq) ans += dp[m + 1][n][k][p], ans %= mod;
    }
  }
  printf("%lld\n", ans);
  return 0;
}

标签:P7961,丽莎,int,题解,read,ch,可爱,NOIP2021,dp
来源: https://www.cnblogs.com/orzpls/p/16320055.html