[NOIP2021] 数列
题目描述#
给定整数 ,和一个长度为 的正整数数组 。
对于一个长度为 ,下标从 开始且每个元素均不超过 的非负整数序列 ,我们定义它的权值为 。
当这样的序列 满足整数 的二进制表示中 的个数不超过 时,我们认为 是一个合法序列。
计算所有合法序列 的权值和对 取模的结果。
数据范围#
对所有测试点保证 ,,。
solution#
按位
由低位向高位考虑
表示讨论了 从低到高的前 位,已经确定了 个序列 中的元素, 从低到高前 位中有 个 ,要向当前讨论位的下一位进位
转移时枚举 中有多少个
注意还有 位后面的 也要统计
复杂度
code#
#include <cstdio>
#include <iostream>
using namespace std;
typedef long long ll;
const ll mod = 998244353;
ll ans, v[105], f[105][35][35][16], fac[105][35];
ll C[35][35];
inline void init(int n) {
for (int i = 0; i <= n; i++) C[i][0] = 1;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= i; j++) C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mod;
}
inline int popcnt(int n) {
int res = 0;
while (n) res += n & 1, n >>= 1;
return res;
}
int main() {
init(30);
int n, m, K;
scanf("%d %d %d", &n, &m, &K);
for (int i = 0; i <= m; i++) {
scanf("%lld", &v[i]);
fac[i][0] = 1;
for (int j = 1; j <= n; j++) fac[i][j] = fac[i][j - 1] * v[i] % mod;
}
f[0][0][0][0] = 1;
for (int i = 0; i <= m; i++)
for (int j = 0; j <= n; j++)
for (int k = 0; k <= K; k++)
for (int p = 0; p <= n >> 1; p++)
for (int t = 0; t <= n - j; t++) f[i + 1][j + t][k + (t + p & 1)][t + p >> 1] = (f[i + 1][j + t][k + (t + p & 1)][t + p >> 1] + f[i][j][k][p] * fac[i][t] % mod * C[n - j][t] % mod) % mod;
for (int k = 0; k <= K; k++)
for (int p = 0; p <= n >> 1; p++)
if (k + popcnt(p) <= K) ans = (ans + f[m + 1][n][k][p]) % mod;
printf("%lld", ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
2021-10-25 CSP 赛后总结