[NOIP2021]数列 题解
Preface
当时在考场上我还看不出来这是 DP,现在能看出来却不会写 qwq。
见识到了新的 DP 处理手法 QAQ,涨姿势了。
(吐槽:为什么 T2,T3 都是 DP o(╥﹏╥)o)
Analysis
(注:为了方便,本文将 中 的个数限制设为 )
这种计数类的问题大概率是 DP,可以往这个方面想。
考虑状态的设计,由于这道题存在进位的问题,而且进位是从低到高的,所以可以按二进制位从低到高考虑。
那么状态里肯定要有两维:,分别表示当前的位数,和已经确定的 中元素的数量。
但是题中对二进制 的个数限制为 ,而且进位相当烦人,这时就可以考虑直接把它们设进状态。
毕竟这题数据范围不大,就算不是正解也能拿不少分。
由此,设计出一个 DP:
设 表示 位已经考虑过,当前考虑第 位, 中已经有 个元素确定,目前 中有 个 ,且从 推过来的进位数为 时的权值和。
初始状态:。
发现这个状态并不是很好从前面转移来,那么我们就用已有的状态往后转移。
考虑在第 位放 个 中的元素,那么 中 的个数会变成 ,向第 位进 个 。
那么接下来的状态就是 。
现在来算一算这次转移的贡献,直接放式子:
这个式子并不难理解,就是在 剩下的 个元素中选 个,会产生 的权值。
剩余要注意的就是统计答案。累加上所有的 。
但因为这题二进制 的个数至多为 ,而且 位及以后显然还会有进位产生的 ,不难发现,这个状态的 中真正的 的个数是 。
所以还要在枚举时判断一下 。
那么这道题就做完了。时间复杂度 ,卡得很紧,组合数和 都要预处理出来。
#include <bits/stdc++.h> using namespace std; typedef long long ll; const ll mod = 998244353; const int maxn = 35; const int maxm = 105; ll C[maxn][maxn]; int n,m,K; ll v[maxm],pw[maxm][maxn],popcnt[maxn]; int lowbit(int x) { return x & -x; } int popcount(int x) { int ans = 0; for(;x;x -= lowbit(x))++ ans; return ans; } ll f[maxm][maxn][maxn][maxn >> 1]; int main() { freopen("sequence.in","r",stdin); freopen("sequence.out","w",stdout); scanf("%d %d %d",&n,&m,&K); for(int i = 0;i <= m;++ i) { scanf("%lld",&v[i]); pw[i][0] = 1ll; for(int j = 1;j <= n;++ j)pw[i][j] = pw[i][j - 1] * v[i] % mod; } for(int i = 0;i <= n;++ i) { C[i][0] = 1ll; for(int j = 1;j <= i;++ j) { C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mod; } popcnt[i] = popcount(i); } f[0][0][0][0] = 1ll; for(int i = 0;i <= m;++ i) { for(int j = 0;j <= n;++ j) { for(int k = 0;k <= K;++ k) { for(int q = 0;q <= (n >> 1);++ q) { for(int t = 0;t <= n - j;++ t) { (f[i + 1][j + t][k + (t + q & 1)][t + q >> 1] += f[i][j][k][q] * C[n - j][t] % mod * pw[i][t] % mod) %= mod; } } } } } ll ans = 0; for(int k = 0;k <= K;++ k) { for(int q = 0;q <= (n >> 1);++ q) { if(k + popcnt[q] <= K) { (ans += f[m + 1][n][k][q]) %= mod; } } } printf("%lld\n",ans); return 0; }
完结撒花✿✿ヽ(°▽°)ノ✿
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通