AtCoder Beginner Contest 221 H. Count Multiset(容斥 dp 拆分数 差分 数形结合)

题目

给定m,n(m<=n<=5e3),

求大小为k的多重集合,满足元素和为n,

且每种数在集合中出现的次数都小于等于m的集合数有多少个

答案对998244353取模

思路来源

官方题解

「解题报告」[ABC221H] Count Multiset - K8He - 洛谷博客

Solution-ABC221H - yllcm 的博客 - 洛谷博客

【AtCoder思维训练】ABC221H Count Multiset - QAQ - 洛谷博客

题解1

整体来说,如果没有每个次数<=m的限制,就是分拆数

1. 把多重集合转成不下降序列(单增序列),

每个序列统计一次(A1,A2,...,Ak)(A1<=A2<=...<=Ak)

2. 把不下降序列转成差分数组,

令B[1]=A[1],B[i]=A[i]-A[i-1],

对于差分数组,需要满足以下三个条件:

\sum_{i=1}^{k}B_{i}*(k+1-i)=n

②B数组中不存在连续的m个0

B_{1}>0

3. 发现①做dp的时候是有后效性的,

与k相关, 第k+1次的时候需要加上前k个的和

考虑对差分数组反转,即令i=k+1-i

反转后的差分数组B,需要满足以下三个条件:

\sum_{i=1}^{k}B_{i}*i=n

②B数组中不存在连续的m个0

B_{k}>0

f[i][j]表示当前选了i个数,总和为j的方案数

①一种方式是,对反转的差分序列后面新增一个0,

如:

原序列2 2 3,差分序列2 0 1,反转差分序列1 0 2,

此时给反转差分序列后面加一个0,得到1 0 2 0,

对应差分序列0 2 0 1,原序列0 2 2 3,即原序列前面加一个0

即f[i][j]从f[i-1][j]转移而来

②另一种方式是,对反转的差分序列的最后一个数加1,

如:

原序列2 2 3,差分序列2 0 1,反转差分序列1 0 2,

此时给反转差分序列最后一个数加1,得到1 0 3,

对应差分序列3 0 1,原序列3 3 4,即原序列整体加1

即f[i][j]从f[i][j-i]转移而来

考虑怎么加上连续最多m个0的限制,

设g[i][j]表示当前填了i个数,总和为j,序列里不含0的方案数,

给整体加1过后的序列,即不包含0,有g[i][j]=f[i][j-i]

f的转移,要么是对f数组整体加1,

要么是钦定0的个数,从一段没有0的g数组转移过来

f[i][j]=f[i][j-i]+\sum_{k=1}^mg[i-k][j]

g[i][j]=f[i][j-i]

由于序列里没有0,最后g[i][n]即为所求

当然,可以进一步化简,

f[i][j]=\sum_{k=0}^mg[i-k][j]

g[i][j]=f[i][j-i]

因为最后是求g数组,可以上式代入下式联立消掉f,有

g[i][j]=f[i][j-i]=\sum_{k=0}^mg[i-k][j-i]

就与官方题解中的代码一致了,前缀和优化一下,复杂度O(n^2)

题解2

接题解1,反转后的差分数组B,需要满足以下三个条件:

\sum_{i=1}^{k}B_{i}*i=n

②B数组中不存在连续的m个0

B_{k}>0

直接g[i][j]表示当前选了i个数,\sum_{x=1}^{i}B_{x}*x=j,最后一个数即b[i]>0的方案数

考虑暴力转移,

从1到m,枚举最后一段0的连续段长度,

也就是枚举上一个非0的位置x,再枚举b[i]选择的数为w,有:

g[i][j]=\sum_{w=1}^{w*i\leq j}\sum_{x=i-m}^{i-1}g[x][j-w*i]

\sum_{x=i-m}^{i-1}g[x][j-w*i]的第一维,也就是g[x]这一维维护前缀和,

即可实现转移,复杂度O(n^2logn)

题解3

考虑直接对原序列做dp,

f[i][j]表示前i个数和为j的方案数

如:原序列1 1 2,

①每次要么新增一个1,转移到1 1 1 2,f[i][j]从f[i-1][j-1]转移

②要么令所有数都+1,使得所有数都大于等于2,转移到2 2 3,f[i][j]从f[i][j-i]转移

但是,第一种转移新增了一个1,可能会导致恰出现连续m+1个1的情况,减掉这种情况即可

出现这种情况时,前m+1个数字为1,且第m+2个数为>=2的值,

只需全局减1,即可删掉m+1个1,并且使得第m+2个数的值>=1,也就对应了f[i-(m+1)][j-i]

f[i][j]=f[i-1][j-1]+f[i][j-i]-f[i-(m+1)][j-i]

复杂度O(n^2)

题解4

数形结合,

如果对原序列dp,如下图所示,有三条限制,

x_{i}\leq x_{i+1},x_{1}> 0

②不存在超过m个xi相同

\sum x_{i}=n

按照箭头视角去看这个图,

也就是先顺时针旋转90度,再翻转,

新的序列仍然有三条限制,

y_{i}\leq y_{i+1},y_{1}> 0

y_{i+1}-y_{i}\leq m

\sum y_{i}=n

发现限制2更强了,所以可以对新序列dp,

dp[i][j]表示最后一列高为i,柱状图面积总和为j的方案数,

枚举上一列高为x,需要满足x∈[i-m,i],有:

dp[i][j]=\sum_{x\leq i,x\geq i-m}dp[x][j-i]

惊奇地发现,这和题解1得到的转移式子一模一样

复杂度O(n^2)

代码1、代码4 O(n^2)

#include<iostream>
using namespace std;
const int N=5e3+10,mod=998244353;
int n,m,dp[N][N],sum[N][N];
void add(int &x,int y){
    x=(x+y)%mod;
}
int main(){
    scanf("%d%d",&n,&m);
    dp[0][0]=sum[0][0]=1;
    for(int i=1;i<=n;++i){
        for(int j=0;j<=n;++j){
            if(j>=i){
                dp[i][j]=sum[i][j-i];
                if(i-m-1>=0){
                    add(dp[i][j],mod-sum[i-m-1][j-i]);
                }
            }
            sum[i][j]=(sum[i-1][j]+dp[i][j])%mod;
        }
    }
    for(int i=1;i<=n;++i){
        printf("%d\n",dp[i][n]);
    }
    return 0;
}

代码2 O(n^2logn)

#include<iostream>
using namespace std;
const int N=5e3+10,mod=998244353;
int n,m,g[N][N],sum[N][N];
void add(int &x,int y){
    x=(x+y)%mod;
}
int main(){
    scanf("%d%d",&n,&m);
    g[0][0]=sum[0][0]=1;
    for(int i=1;i<=n;++i){
        for(int j=0;j<=n;++j){
            for(int w=1;w*i<=j;++w){
                add(g[i][j],sum[i-1][j-w*i]);
                if(i-m-1>=0)add(g[i][j],mod-sum[i-m-1][j-w*i]);
            }
            sum[i][j]=(sum[i-1][j]+g[i][j])%mod;
        }
    }
    for(int i=1;i<=n;++i){
        printf("%d\n",g[i][n]);
    }
    return 0;
}

代码3 O(n^2)

#include<iostream>
using namespace std;
const int N=5e3+10,mod=998244353;
int n,m,dp[N][N];
void add(int &x,int y){
    x=(x+y)%mod;
}
int main(){
    scanf("%d%d",&n,&m);
    dp[0][0]=1;
    for(int i=1;i<=n;++i){
        for(int j=1;j<=n;++j){
            dp[i][j]=dp[i-1][j-1];
            if(j-i>=0)add(dp[i][j],dp[i][j-i]);
            if(i>=m+1 && j-i>=0)add(dp[i][j],mod-dp[i-(m+1)][j-i]);
        }
    }
    for(int i=1;i<=n;++i){
        printf("%d\n",dp[i][n]);
    }
    return 0;
}

代码5 O(n^3)

自己乱搞了两个复杂度并不正确的做法,也贴在这里好了

这个是考虑容斥减掉不合法的答案

#include<iostream>
using namespace std;
const int N=5e3+10,mod=998244353;
typedef long long ll;
int n,m,dp[N][N],sum[N];//dp[i][j]选了i个和为j方案数
void add(int &x,int y){x=(x+y)%mod;}
int main(){
    scanf("%d%d",&n,&m);
    dp[0][0]=1;
    for(int l=1;l<=n;++l){
        for(int i=1;i<=n;++i){
            for(int j=l;j<=n;++j){
                add(dp[i][j],dp[i-1][j-l]);
                /*
                for(int k=1;k<=j;++k){
                    add(dp[i][j],dp[i-1][j-k]);
                }
                */
            }
        }
        for(int i=n;i>=m+1;--i){
            for(int j=n;j-l*(m+1)>=0;--j){
                add(dp[i][j],mod-dp[i-(m+1)][j-l*(m+1)]);   
            }
        }
    }
    // for(int i=1;i<=n;++i){
    //     for(int j=1;j<=n;++j){
    //         printf("i:%d j:%d dp:%d\n",i,j,dp[i][j]);
    //     }
    // }
    for(int i=1;i<=n;++i){
        printf("%d\n",dp[i][n]);
    }
    return 0;
}

代码6 O(n^3logn)

这个是纯纯暴力

#include<iostream>
using namespace std;
const int N=5e3+10,mod=998244353;
typedef long long ll;
int n,m,dp[N][N];//dp[i][j]选了i个和为j方案数
void add(int &x,int y){x=(x+y)%mod;}
int main(){
    scanf("%d%d",&n,&m);
    dp[0][0]=1;
    for(int i=1;i<=n;++i){
        for(int j=n;j>=i;--j){
            for(int k=1;k<=m;++k){
                if(j-k*i<0)break;
                for(int l=n;l>=k;--l){
                    add(dp[l][j],dp[l-k][j-k*i]);
                }
            }
        }
    }
    for(int i=1;i<=n;++i){
        printf("%d\n",dp[i][n]);
    }
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/339742.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【RT-DETR有效改进】遥感旋转网络 | LSKNet动态的空间感受野网络(轻量又提点)

前言 大家好&#xff0c;我是Snu77&#xff0c;这里是RT-DETR有效涨点专栏。 本专栏的内容为根据ultralytics版本的RT-DETR进行改进&#xff0c;内容持续更新&#xff0c;每周更新文章数量3-10篇。 专栏以ResNet18、ResNet50为基础修改版本&#xff0c;同时修改内容也支持Re…

掌上单片机实验室 – 低分辨率编码器测速方式完善(24)

一、背景 本以为“掌上单片机实验室”这一主题已告一段落&#xff0c;可最近在测试一批新做的“轮式驱动单元”时&#xff0c;发现原来的测速算法存在问题。 起因是&#xff1a;由于轮式驱动单元的连线较长&#xff0c;PCB体积也小&#xff0c;导致脉冲信号有干扰&#xff0c;加…

Linux系统监控:保障稳定性与性能的关键

Linux操作系统作为广泛应用于服务器和嵌入式设备的开源操作系统&#xff0c;对于系统监控的需求尤为重要。通过对Linux系统进行有效的监控&#xff0c;管理员可以实时了解系统的运行状态、识别潜在问题并采取相应的措施。本文将介绍Linux系统监控的基本原理、常用工具和关键指标…

央视推荐的护眼台灯是哪款?学生专用台灯第一品牌

近视问题在我国十分严重&#xff0c;据相关调查数据显示&#xff0c;我国有7亿近视人口。特别是在现代&#xff0c;青少年成为近视高发人群&#xff0c;其中大部分近视的原因与长时间不正确用眼导致的眼睛疲劳有关。台灯作为许多家庭中的小家电&#xff0c;不论是上班族还是孩子…

一文搞懂Microsoft Copilot品种及定价说明

Microsoft Copilot 是一个 AI 助手&#xff0c;提供跨 Microsoft Cloud 的创新解决方案。Copilot 使复杂的任务更易于管理&#xff0c;从而促进协作环境并增强用户体验。 目前Copilot一共有这么几种&#xff1a; 一、必应中的copilot 在edge浏览器侧边栏中使用&#xff0c;这…

ESP32-TCP服务端(Arduino)

将ESP32设置为TCP服务器 介绍 TCP&#xff08;Transmission Control Protocol&#xff09;传输控制协议&#xff0c;是一种面向连接的&#xff08;一个客户端对应一个服务端&#xff09;、可靠的传输层协议。在TCP的工作原理中&#xff0c;它会将消息或文件分解为更小的片段&a…

通俗易懂理解小波池化/WaveCNet

重要说明&#xff1a;本文从网上资料整理而来&#xff0c;仅记录博主学习相关知识点的过程&#xff0c;侵删。 一、参考资料 github代码&#xff1a;WaveCNet 通俗易懂理解小波变换(Wavelet Transform) 二、相关介绍 关于小波变换的详细介绍&#xff0c;请参考另一篇博客&…

大模型学习之书生·浦语大模型6——基于OpenCompass大模型评测

基于OpenCompass大模型评测 关于评测的三个问题Why/What/How Why What 有许多任务评测&#xff0c;包括垂直领域 How 包含客观评测和主观评测&#xff0c;其中主观评测分人工和模型来评估。 提示词工程 主流评测框架 OpenCompass 能力框架 模型层能力层方法层工具层 支持丰富…

使用Go发送HTTP GET请求

在Go语言中&#xff0c;我们可以使用net/http包来发送HTTP GET请求。以下是一个简单的示例&#xff0c;展示了如何使用Go发送HTTP GET请求并获取响应。 go复制代码 package main import ( "fmt" "io/ioutil" "net/http" …

用BK7251播放音乐

单片机的第一道难关无疑是烧录&#xff0c;如果烧录解决了&#xff0c;那么就有资格挑战各种坑了。 BK7251播放MP3 一、折腾材料 1、软件SDK&#xff1a; bk7251_audio_release_20190826_0701&#xff08;BK7251 rtt sdk&#xff09;&#xff0c;可以从github&#xff0c;gite…

HCIP网络的类型

一.网络类型&#xff1a; 点到点 BMA&#xff1a;广播型多路访问 -- 在一个MA网络中同时存在广播&#xff08;泛洪&#xff09;机制 NBMA&#xff1a;非广播型多路访问 -- 在一个MA网络中&#xff0c;没有泛洪机制-----不怎么使用了 MA&#xff1a;多路访问 -- 在一个…

基于光口的以太网 udp 回环实验

文章目录 前言一、系统框架整体设计二、系统工程及 IP 创建三、UDP回环模块修改说明四、接口讲解五、顶层模块设计六、下载验证前言 本章实验我们通过网络调试助手发送数据给 FPGA,FPGA通过光口接收数据并将数据使用 UDP 协议发送给电脑。 提示:任何文章不要过度深思!万事万…

电工技术实验-电路元件伏安特性测绘

一、 实验目的 1、学会识别常用电路元件的方法 2、验证线性电阻、非线性电阻元件的伏安特性 3、熟悉实验台上直流电工仪表和设备的使用方法 二、实验器材 可调直流稳压电源、直流数字毫安表、直流数字电压表、万用表 二极管、稳压管、白炽灯、线性电阻 三、实验原理 任…

低压防雷箱综合选型应用方案

低压防雷箱是一种用于保护低压配电系统免受雷电过电压的影响的装置&#xff0c;它主要由防雷箱模块、浪涌保护器SPD、接地线等组成。本文将介绍低压防雷箱的作用原理和行业应用解决方案&#xff0c;以及低压防雷箱的选型方法。 低压防雷箱的作用原理 低压防雷箱的作用原理是利…

革新区块链:代理合约与智能合约升级的未来

作者 张群&#xff08;赛联区块链教育首席讲师&#xff0c;工信部赛迪特聘资深专家&#xff0c;CSDN认证业界专家&#xff0c;微软认证专家&#xff0c;多家企业区块链产品顾问&#xff09;关注张群&#xff0c;为您提供一站式区块链技术和方案咨询。 代理合约&#xff08;Prox…

职业规划,软件开发工程师的岗位任职资格

软件工程师是指从事软件开发的人&#xff0c;主要的工作涉及到项目培训和项目设计两个方面。在实际工作中&#xff0c;软件工程师是一个广义的概念&#xff0c;包括了很多与软件相关的人员。除开最基础的编程语言&#xff0c;还有数据库语言等等。从事这份工作&#xff0c;需要…

多标签节点分类

Multi-Label Node Classification on Graph-Structured Data,TMLR’23 Code 学习笔记 图结构数据的多标签分类 节点表示或嵌入方法 通常会生成查找表&#xff0c;以便将相似的节点嵌入的更近。学习到的表示用作各种下游预测模块的输入特征。 表现突出的方法是基于随机游走(ran…

【Spring 篇】MyBatis注解开发:编写你的数据乐章

欢迎来到MyBatis的音乐殿堂&#xff01;在这个充满节奏和韵律的舞台上&#xff0c;注解是我们编写数据乐章的得力助手。无需繁琐的XML配置&#xff0c;通过简单而强大的注解&#xff0c;你将能够轻松地与数据库交互。在这篇博客中&#xff0c;我们将深入探讨MyBatis注解开发的精…

MySQL数据库 | 事务中的一些问题(重点)

文章目录 什么是事务&#xff1f;事务的几个特性(ACID) -重点原子性(Atomicity)一致性(Consistency)隔离性(Isolation)持久性(Durability) Mysql中事务操作隐式事务显式事务 savepoint关键字只读事务事务中的一些问题&#xff08;重点&#xff09;隔离级别脏读解决办法 幻读解决…

C语言实战系列一:经典贪食蛇

C语言学习必须实战&#xff0c;并且学完语法后就必须立即用实战来巩固。一般需要10来个比较复杂的程序才能掌握C语言。今天就教大家第一个小程序&#xff0c;贪食蛇。 首先上代码 一、代码 #include <stdio.h> #include <stdlib.h> #include <curses.h> #…