P5664 [CSP-S2019] Emiya 家今天的饭 题解

news/2025/10/8 23:01:47/文章来源:https://www.cnblogs.com/petercode-314/p/19130217

题目传送门

洛谷 P5664

前言

本题解为作者整合了自己学习其他题解后为自己写的用以复习的笔记,不喜勿喷谢谢,但是有逻辑错误或语言不清晰之处欢迎提出!

题目描述

Emiya 是个擅长做菜的高中生,他共掌握 \(n\)烹饪方法,且会使用 \(m\)主要食材做菜。为了方便叙述,我们对烹饪方法从 \(1 \sim n\) 编号,对主要食材从 \(1 \sim m\) 编号。

Emiya 做的每道菜都将使用恰好一种烹饪方法与恰好一种主要食材。更具体地,Emiya 会做 \(a_{i,j}\) 道不同的使用烹饪方法 \(i\) 和主要食材 \(j\) 的菜(\(1 \leq i \leq n\)\(1 \leq j \leq m\)),这也意味着 Emiya 总共会做 \(\sum\limits_{i=1}^{n} \sum\limits_{j=1}^{m} a_{i,j}\) 道不同的菜。

Emiya 今天要准备一桌饭招待 Yazid 和 Rin 这对好朋友,然而三个人对菜的搭配有不同的要求,更具体地,对于一种包含 \(k\) 道菜的搭配方案而言:

  • Emiya 不会让大家饿肚子,所以将做至少一道菜,即 \(k \geq 1\)
  • Rin 希望品尝不同烹饪方法做出的菜,因此她要求每道菜的烹饪方法互不相同
  • Yazid 不希望品尝太多同一食材做出的菜,因此他要求每种主要食材至多在一半的菜(即 \(\lfloor \frac{k}{2} \rfloor\) 道菜)中被使用

这些要求难不倒 Emiya,但他想知道共有多少种不同的符合要求的搭配方案。两种方案不同,当且仅当存在至少一道菜在一种方案中出现,而不在另一种方案中出现。

Emiya 找到了你,请你帮他计算,你只需要告诉他符合所有要求的搭配方案数对质数 \(998,244,353\) 取模的结果。
这里的 \(\lfloor x \rfloor\) 为下取整函数,表示不超过 \(x\) 的最大整数。

题意简化

给定一个 \(n\)\(m\) 列的矩阵 \(a\) ,每行 \(i\)至多选择某一列 \(j\)\(a_{i,j}\) 种可能中的1个,求有多少种方案满足以下3个约束。

  1. 至少选择一个
  2. 每行至多选一个
  3. 每列最多选总数的一半

思路

直接计数dp。目标时间复杂度: \(\text O(mn^2)\)
注意到约束3过于讨嫌难以处理,所以 正难则反 ,考虑容斥原理:
对于约束3,若违反,则说明此列中有超过一半的菜,所以其他列肯定是少于一半,符合要求的。
既然如此,我们就枚举是哪一列违反了约束3,统计这些不合法方案总数,最后用总方案数减去即得答案。

统计总方案数

具体的,令 \(tot[i][j]\) 表示前 \(i\) 行中,选择了 \(j\) 次的方案数,注意 \(j\) 次等价于选了 \(j\) 行,因为每行只能选一个。
则转移方程考虑两种情况:

  1. 这一行没选
  2. 这一行选了某一个菜

故有:

\[tot[i][j]=tot[i-1][j]+tot[i-1][j-1]\times s[i] \]

,其中 \(s[i]\) 表示第 \(i\) 行中的总菜数,即

\[s[i]=\sum_{j=1}^{m}a[i][j] \]

统计非法方案

对于第 \(col\) 列,令 \(dp[i][j][k]\) 代表前 \(i\) 行中选了 \(j\)\(col\) 的菜品,选了 \(k\) 个其他菜的菜品。
则考虑三种情况:

  1. 这一行啥都没选
  2. 这一行选了 \(col\) ,总共有 \(a[i][col]\) 种可能选择,乘法原理
  3. 这一行没选 \(col\) 但选了其他的,总共有 \(s[i]-a[i][col]\) 种可能选择,同样乘法原理开大怼上去

于是有:

\[dp[i][j][k]=dp[i-1][j][k]+dp[i-1][j-1][k]\times a[i][col]+dp[i-1][j][k-1]\times(s[i]-a[i][col]) \]

优化

这个优化比较玄学,也是我写这篇题解的主要搞懂对象。
注意到非法方案满足 \(j>k\) ,即 \(j-k>0\)
换言之,我们只需维护 \(j-k\) ,不需要真正关注 \(j,k\) 的值。
那么,令 \(dp[i][\triangle x]\) 代表前 \(i\) 行中,选了菜品 \(col\) 的减去选了菜品 \(col\) 之外的值为 \(\triangle x\) 的方案数。
转移方程需考虑三种情况:

  1. 这一行啥都没选,直接继承 \(dp[i-1][\triangle x]\)
  2. 这一行选了 \(col\)\(\triangle x\)\(1\)
  3. 这一行选了 \(col\) 之外的, \(\triangle x\)\(1\)

如何证明这囊括了所有情况,不重不漏呢?
这个我也不会,如果有知道的麻烦在评论区不吝赐教,谢谢!

总之,新的转移方程挺显然的(用 \(j\) 代替 \(△x\)):

\[dp[i][j]=dp[i-1][j]+dp[i-1][j-1]\times a[i][col]+dp[i-1][j+1]\times(s[i]-a[i][col]) \]

最后,注意到 \(dp[i][j]\) 中的 \(-n\leq j\leq n\) ,所以给 \(dp[i][j]\)\(j\) 强行都加 \(n\)
那么最后符合非法方案的就从 \(j>0\) 变成 \(j>n\) ,即最后减方案数减的是

\[\sum_{j=n+1}^{2n}dp[n][j] \]

AC 代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M = 998244353;
const int N = 105, A = 2005;
int n, m;
ll a[N][A], s[N];
// tot[i][j]: 前i种烹饪方法中选了j个食材的总方案数
ll tot[N][N];
// dp[i][j+n]: 前i种烹饪方法中超限的食材出现次数减去其他食材出现次数为j的非法方案数
ll dp[N][N * 2];
int main()
{ios::sync_with_stdio(false);cin.tie(0);cin >> n >> m;for (int i = 1; i <= n; ++i) {for (int j = 1; j <= m; ++j) {cin >> a[i][j];(s[i] += a[i][j]) %= M;}// printf("There are %lld ways to cook with way %d\n", s[i], i);}tot[0][0] = 1;for (int i = 1; i <= n; ++i) {tot[i][0] = tot[i - 1][0];for (int j = 1; j <= n; ++j) {tot[i][j] = tot[i - 1][j] + tot[i - 1][j - 1] * s[i] % M;tot[i][j] %= M;// printf("There's %lld ways to pick %d columns from the first %d rows.\n", tot[i][j], i, j);}}// printf("tot:\n");// for (int i = 1; i <= n; ++i) {// 	for (int j = 0; j <= n; ++j) {// 		printf("%lld\t", tot[i][j]);// 	}// 	printf("\n");// }ll ans = 0;for (int col = 1; col <= m; ++col) {// printf("If %d is the invalid ingredient:\n", col);memset(dp, 0, sizeof(dp));dp[0][n] = 1;for (int i = 1; i <= n; ++i) {for (int j = n - i; j <= n + i; ++j) {dp[i][j] = dp[i - 1][j];(dp[i][j] += dp[i - 1][j - 1] * a[i][col] % M) %= M;(dp[i][j] += dp[i - 1][j + 1] * (s[i] - a[i][col]) % M) %= M;// for (int k = 1; k <= m; ++k) {// 	dp[i][j][k] = dp[i - 1][j][k] + dp[i - 1][j - 1][k] * a[i][j] + dp[i - 1][j][k - 1] * (s[i] - a[i][j]);// }}}// printf("DP:\n");// for (int i = 1; i <= n; ++i) {// 	for (int j = n - i; j <= n + i; ++j) {// 		printf("dp[%d][%d]: %lld\t", i, j - n, dp[i][j]);// 	}// 	printf("\n");// }for (int i = 1; i <= n; ++i)(ans -= dp[n][i + n]) %= M;ans = (ans % M + M) % M;}for (int i = 1; i <= n; ++i) {(ans += tot[n][i]) %= M;}cout << ans << '\n';return 0;
}

后记

这里其实可以滚一下,把dp第一维压到2,用奇偶滚一下的说但是没必要
证明差分dp可行目前我能想到的只有暴力打印每次迭代的dp数组去看是不是满足j-k为定值的都相等/加起来怎么怎么样的,有知道具体方法的务必留一下,谢谢!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网站建设艾瑞市场分析英国设计网站

目录 Optional 的方法 Optional实例 《天道》丁元英经典语录 所谓真经,就是能够达到寂空涅盘的究竟法门。可悟不可修。修为成佛,在求。悟为明性,在知。修行以行制性。悟道以性施行。觉者由心生律;修者以律制心,不落恶果者有信无证,住因住果,住念住心,如是生灭。不昧…

谷歌网站开发用什么框架next wordpress

近日&#xff0c;JetBrains 对外发布两项重要产品更新&#xff1a;专为云端和其他服务器打造的远程开发解决方案&#xff0c;以及轻量级编辑器Fleet。 为IntelliJ 平台引入远程开发支持 在近期陆续发布的2021.3 版本的各 IDE 中&#xff0c;JetBrains 向 IntelliJ 平台添加了远…

PWN手的成长之路-11-CISCN 2019华北 PWN1-栈溢出

远程连接以下靶机,看看交互。file 查看程序文件。checksec 查看程序文件安全属性。开启了 NX 保护,栈上不可执行。IDA 打开程序文件。查看 ain 函数,发现调用了 func 函数。查看 func 函数。这里需要判断 v2 是否等…

sensitive-word:一个简单易用的敏感词过滤框架

这篇文章,分享一个开源项目:sensitive-word 。Github 地址:https://github.com/houbb/sensitive-wordsensitive-word 是一个功能强大的 Java 敏感词过滤框架,它不仅提供了基础的敏感词检测功能,还支持单词标签分类…

回归学习——包机制

回归学习 包机制 包的本质就是文件夹,用来区别类名的命名空间。一个文件在写的时候要把包写在最前面,一般利用公司倒置作为包名,为了能够使用一个包的成员,我们需要在Java程序中明确导入该包,方式为使用‘import语…

哈尔滨中小企业网站制作长沙知名网站

无论是前面学习的序列式容器,还是关联式容器,要想实现遍历操作,就必须要用到该类型容器的迭代器。当然,map 容器也不例外。C++ STL 标准库为 map 容器配备的是双向迭代器(bidirectional iterator)。这意味着,map 容器迭代器只能进行 ++p、p++、--p、p--、*p 操作,并且迭…

网站建设职责网站源码大全

一、需求 用户输入四个季度的数据&#xff0c;根据数据生成柱形统计图&#xff0c;浏览器预览效果如下 二、完整代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content&q…

wordpress动漫主题秦皇岛seo排名

二叉树相关推荐 107.二叉树的层次遍历II199.二叉树的右视图637.二叉树的层平均值429.N叉树的层序遍历515.在每个树行中找最大值116.填充每个节点的下一个右侧节点指针117.填充每个节点的下一个右侧节点指针II总结 107.二叉树的层次遍历II 切片本质是一个结构体&#xff0c;包含…

vue 组件的常见8种通信方式

1、通过props传递‌,emit触发自定义事件: 父传子:子组件中通过props接收父组件传递的数据。 ‌子传父:子组件通过emit触发一个事件,父组件监听这个事件来接收数据。 vue2:通过props和$emit vue3:script中setup,…

技能训练企业网站建设可行性分析企业网站建设 百度文库

文章目录 参考环境常量数组不可变性版本限制 constdefine()构造大小写不敏感的常量$case_insensitive 参数PHP7.3PHP8 若 define() 在不支持常量数组的版本中运行 参考 项目描述搜索引擎Bing、GoogleAI 大模型文心一言、通义千问、讯飞星火认知大模型、ChatGPTPHP 手册PHP Man…

251008

251008美好的一天从现在开始

vue一键安装

vue一键安装 Microsoft Windows [版本 10.0.26100.4946] (c) Microsoft Corporation。保留所有权利。F:\vue_flask_project\vue_flask_project_one\vue>npm install --global vue-cli npm warn deprecated inflight…

佛山网站建设找哪家wordpress 中文版下载

内联式css样式&#xff0c;直接写在现有的HTML标签中 CSS样式可以写在哪些地方呢&#xff1f;从CSS 样式代码插入的形式来看基本可以分为以下3种&#xff1a;内联式、嵌入式和外部式三种。这一小节先来讲解内联式。 内联式css样式表就是把css代码直接写在现有的HTML标签中&am…

权威的网站建设排行榜男科医院哪家正规医院

模拟伪造请求 方法一&#xff1a;打断点模拟HTTP请求 1、浏览器页面填好内容后&#xff08;不要操作提交&#xff09;&#xff0c;打开fiddler&#xff0c;设置请求前断点&#xff0c;点击菜单fiddler,”Rules”\”Automatic Breakpoints”\”Before Requests” 2、在页面上点…

做网站卖电脑oss cdn wordpress

目录 一、Vite概述 二、Vite构建Vue3工程化项目 三、ViteVue3项目目录结构 四、ViteVue3项目组件&#xff08;SFC入门&#xff09; 五、ViteVue3样式导入方式 六、ViteVue3响应式数据和setup语法糖 一、Vite概述 Vite是一种新型前端构建工具,能够显著提升前端开发体验;Vite结合…

网站页面设计要求wordpress快速登陆插件

动机(Motivate)&#xff1a; 在软件构建过程中&#xff0c;一个请求可能被多个对象处理&#xff0c;但是每个请求在运行时只能有一个接受者&#xff0c;如果显示指定&#xff0c;将必不可少地带来请求发送者与接受者的紧耦合。 如何使请求的发送者不需要指定具体的接受…

如何使用 ManySpeech 调用 SenseVoiceSmall 模型

一、模型与组件简介SenseVoice 模型多语言音频理解开源模型,支持语音识别、语种识别、情感识别等功能,适用于中、粤、英、日、韩等语言。 ManySpeech.AliParaformerAsrC# 语音识别推理库,支持 paraformer-large、pa…

北京免费发布企业信息网站建设网站哪家强

vmware与windows共享文件夹 宗旨&#xff1a;技术的学习是有限的&#xff0c;分享的精神是无限的。 虚拟工具安装好之后&#xff0c;我们就可以在windows和linux设置一个共享目录了,继续看图干活。 设置好共享目录以后&#xff0c;打开终端输入以下命令&#xff0c;就可以再…

维基框架 (Wiki Framework) v1.1.2 | 企业级微服务开发框架

Release Notes 版本修复日志【修复】修复HTTPS请求参数ContentType创建错误问题; 【修复】修复用户接口类 IUserDetailsService 被删除问题; 【修复】修复Spring Boot 全局响应处理增加对返回字符串兼容; 【修复】修…

宁夏公路建设局网站wordpress 中国风

Dubbo 支持哪些协议&#xff0c;每种协议的应用场景&#xff0c;优缺点&#xff1f; • dubbo&#xff1a; 单一长连接和 NIO 异步通讯&#xff0c;适合大并发小数据量的服务调用&#xff0c;以及消费者远大于提供者。传输协议 TCP&#xff0c;异步&#xff0c;Hessian 序列化…