[题解] [ABC221H] Count Multiset - DP
[ABC221H] Count Multiset
题面翻译
输入两个正整数 \(N,M\),并存在一个集合,问你一个长度为 \(k\) 的合法集合存在多少个?你需要回答 \(k\) 的值为 \(1\) 到 \(N\) 的每种情况。
一个合法的集合定义指长度为 \(k\),元素和为 \(N\),每一个数字在集合中出现的次数都小于等于 \(M\) 的集合。
题目描述
正の整数 $ N $, $ M $ が与えられます。
$ k=1,2,\ldots,N $ について以下の値を求め、$ 998244353 $ で割ったあまりをそれぞれ出力してください。
- $ k $ 個の正整数からなる多重集合 $ A $ のうち、以下の $ 2 $ つの条件をすべて満たすものの個数
- $ A $ に含まれる要素の総和は $ N $
- 任意の正整数 $ x $ について、$ A $ は $ x $ を高々 $ M $ 個しか含まない
输入格式
入力は以下の形式で標準入力から与えられる。
$ N $ $ M $
输出格式
$ N $ 行に渡って出力せよ。$ i\ (1\ \leq\ i\ \leq\ N) $ 行目には、$ k=i $ の場合の答えを出力すること。
样例 #1
样例输入 #1
4 2
样例输出 #1
1
2
1
0
样例 #2
样例输入 #2
7 7
样例输出 #2
1
3
4
3
2
1
1
提示
制約
- $ 1\ \leq\ M\ \leq\ N\ \leq\ 5000 $
- 入力はすべて整数
Sample Explanation 1
- $ k=1 $ のとき、問題文中の条件を満たすような多重集合 $ A $ は $ {4} $ の $ 1 $ 通りです。 - $ k=2 $ のとき、問題文中の条件を満たすような多重集合 $ A $ は $ {1,3} $ と $ {2,2} $ の $ 2 $ 通りです。 - $ k=3 $ のとき、問題文中の条件を満たすような多重集合 $ A $ は $ {1,1,2} $ の $ 1 $ 通りです。 - $ k=4 $ のとき、問題文中の条件を満たすような多重集合 $ A $ は $ 1 $ つも存在しません。
解析
一道神奇的 dp 题。有个神奇的转移方式。
看到题目直接联想到背包,但发现 相同元素不超过 \(m\) 这个限制条件很毒瘤。无法用背包转移。然后死活想不出来其他方法。
根据题解,我们不按照背包的思路想,就把他看成一段序列,元素为非负整数(如果有负数,那么每一种情况都有无穷种方案)。令 \(dp[i][j]\) 表示集合里有 \(i\) 个元素,和为 \(j\) 的方案数。考虑在整个序列里添加 \(0\),那么它只对 \(i\) 有贡献,可以得到:\(dp[i][j]+=\sum\limits_{k=1}^{m}dp[i-k][j]\)。但只有 0 不够,考虑在序列里的每一个数加 \(1\),那么它只对 \(j\) 有贡献,可以得到:\(dp[i][j]+=dp[i][j-i]\)。
但还有个 相同元素不超过 \(m\) 这个限制条件,我们不知道一个 \(dp\) 序列里有多少个 \(0\),所以需要再开个数组 \(g[i][j]\) 表示没有元素为 \(0\) 的方案数。如何让元素不为 \(0\) 呢?把每个元素 \(+1\) 即可。于是有:
dp[i][j]&=dp[i][j-i]+\sum_{k=1}^{m}dp[i-k][j]\\
g[i][j]&=dp[i][j-1]
\end{split}
\]
如果直接 for 硬套的话,复杂度为 \(O(N^2M)\)。会超。
70 TLE 代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
constexpr int N = 5010, M = 998244353;
int n, m, dp[N][N], g[N][N];
signed main(){
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin>>n>>m;
for(int i=1; i<=m; ++i) dp[i][0] = 1ll;
for(int i=1; i<=n; ++i){
for(int j=1; j<=n; ++j){
if(j >= i){
g[i][j] = (g[i][j] + dp[i][j-i]) % M;
dp[i][j] = (dp[i][j] + dp[i][j-i]) % M;
}
for(int k=1; k<=m && i-k>=0; ++k){
dp[i][j] = (dp[i][j] + g[i-k][j]) % M;
}
}
}
for(int i=1; i<=n; ++i) cout<<g[i][n]<<'\n';
return 0;
}
对于那个最内层循环,可以使用前缀和优化,使复杂度分摊到每一次循环 \(O(1)\),于是总复杂度 \(O(N^2)\),对了,本题不能开 long long,会爆空间。
AC code
#include<bits/stdc++.h>
using namespace std;
constexpr int N = 5001, M = 998244353;
int n, m, dp[N][N], g[N][N], sum[N][N];
int main(){
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin>>n>>m;
for(int i=1; i<=m; ++i) dp[i][0] = 1ll;
for(int i=1; i<=n; ++i){
for(int j=1; j<=n; ++j){
if(j >= i){
g[i][j] = (g[i][j] + dp[i][j-i]) % M;
dp[i][j] = (dp[i][j] + dp[i][j-i]) % M;
}
sum[i][j] = (sum[i-1][j] + g[i][j]) % M;
dp[i][j] = (__int128)(dp[i][j] + sum[i-1][j] - sum[max(i-m-1, 0)][j]) % M;
}
}
for(int i=1; i<=n; ++i) cout<<g[i][n]<<'\n';
return 0;
}
小结:
- 不要过于思维定式。如果发现一个方案不可行或很难行要跳出来另找其他方案。
- 对于求转移方程,可以考虑控制变量,即只对某一变量产生贡献,最后再将贡献合并。很好的思路,只是比较难想。
define int long long不要再用了。- 计算空间复杂度。
[题解] [ABC221H] Count Multiset - DP的更多相关文章
- 【题解】POJ1934 Trip (DP+记录方案)
[题解]POJ1934 Trip (DP+记录方案) 题意: 传送门 刚开始我是这么设状态的(谁叫我DP没学好) \(dp(i,j)\)表示钦定选择\(i\)和\(j\)的LCS,然而你会发现这样钦定 ...
- 【题解】剪纸条(dp)
[题解]剪纸条(dp) HRBUST - 1828 网上搜不到题解?那我就来写一篇吧哈哈哈 最优化问题先考虑\(dp\),设\(dp(i)\)表示将前\(i\)个字符(包括\(i\))分割成不相交的回 ...
- 【题解】地精部落(DP)
[题解]地精部落(DP) 设\(f_i\)表示强制第一个是谷的合法方案数 转移枚举一个排列的最大值在哪里,就把序列分成了互不相干的两个部分,把其中\(i-1\choose j-1\)的数字分配给前面部 ...
- LeetCode题解38.Count and Say
38. Count and Say The count-and-say sequence is the sequence of integers beginning as follows: 1, 11 ...
- bzoj 2669 题解(状压dp+搜索+容斥原理)
这题太难了...看了30篇题解才整明白到底咋回事... 核心思想:状压dp+搜索+容斥 首先我们分析一下,对于一个4*7的棋盘,低点的个数至多只有8个(可以数一数) 这样的话,我们可以进行一个状压,把 ...
- noi省选 [九省联考2018]一双木棋题解(状压dp)
比浙江简单多了........ 题目转送:https://www.luogu.org/problemnew/show/P4363 分析: 我们注意到n和m都很小,考虑一下状压dp. 显然,棋子摆成的形 ...
- 『count 区间dp』
count Description 既然是萌萌哒 visit_world 的比赛,那必然会有一道计数题啦! 考虑一个N个节点的二叉树,它的节点被标上了1-N的编号. 并且,编号为i的节点在二叉树的前序 ...
- 理想乡题解 (线段树优化dp)
题面 思路概述 首先,不难想到本题可以用动态规划来解,这里就省略是如何想到动态规划的了. 转移方程 f[i]=min(f[j]+1)(max(i-m,0)<=j<i 且j符合士兵限定) 注 ...
- CF 1400F x-prime Substrings 题解【AC自动机+DP】
CF 1400F.x-prime Substrings 题意: 给定一个由\('1'\)到\('9'\)组成的字符串\(s\)和一个数\(x\),定义一个串为\(x-prime\)串,当且仅当这个串上 ...
- BZOJ 1087 题解【状压DP】
1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 3112 Solved: 1816[Submit][ ...
随机推荐
- gradle打包命令含离线模式
gradle打包命令gradlew clean 清理gradlew clean build -x test --refresh-dependencies 离线方式: gradlew --offline ...
- #PowerBi Superchange PowerBi 数据模型篇(1)
在过去,业务人员通常不熟悉数据建模,因为数据建模往往是专业的IT人员的领域.但是,得益于POWERBI和POWER PIVOT FOR EXCEL ,这样的日子一去不复返了.那么,什么是数据模型呢? ...
- XAF 属性编辑器(PropertyEditor)- 原理篇
前言 随着 DEV24.1.3 的发布,XAF Blazor 中的属性编辑器(PropertyEditor)也进行了很大的改动,在使用体验上也更接近 WinForm 了,由于进行了大量的封装,理解上没 ...
- Pycharm或cmd在Terminal中运行tensorboard、pip等python包
这个主要是添加python包的路径到环境变量里 因为装了anaconda,所以我们要找的是对应虚拟环境里的包路径,一般是放在anaconda安装路径下的anaconda3\envs\环境名\Scrip ...
- k8s中的亲和性、污点与容忍(调度到不同的宿主机)
本文章并未经过严格实践,如有错误,辛苦指出. 背景 服务需要多副本,来保证高可靠.多活. 那么问题来了,假如这些副本都在同一个宿主机上,或者同一个交换机下-宿主机.交换机其中一项坏掉了,那多副本还有什 ...
- gerrit权限控制
gerrit权限控制 背景 在公司中使用到了Gerrit作为技术管理,在配置的时候发现一些问题:转载了这篇文章作为学习. 正文开始 原文链接:https://blog.csdn.net/chenjh2 ...
- linux 4.19 ip重组
IP重组 ip重组这部分 4.19内核与3.10内核有些差别,4.9.134以后内核中不使用低水位和工作队列了,同时使用了rhashtable 替代了 hash bucket的概念,在3.10内核中使 ...
- 核对不同文件夹所含内容的差异并提取缺失内容:Python代码
本文介绍基于Python语言,以一个大文件夹作为标准,对另一个大文件夹所包含的子文件夹或文件加以查漏补缺,并将查漏补缺的结果输出的方法. 首先,来明确一下本文所需实现的具体需求.现有一个大文件 ...
- yb课堂之用户登陆校验拦截器开发 《十一》
开发对应的登陆拦截器 开发loginInterceptor 登陆校验成功放行 登陆不成功返回json数据 LoginInterceptor.java package net.ybclass.onlin ...
- win10打不出中文的修复方法!
说明 在Win10系统中,默认自带了中文输入法,使用起来非常的方便,但有时win10系统中自带的输入法会打不出中文的情况,该怎么办呢?遇到这样的问题,我们可以参考下本文中的方法来修复. 步骤: cmd ...