题目

题目链接:https://www.luogu.org/problem/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\) 道菜)中被使用

这里的 \(\lfloor x \rfloor\) 为下取整函数,表示不超过 \(x\) 的最大整数。

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

Emiya 找到了你,请你帮他计算,你只需要告诉他符合所有要求的搭配方案数对质数 \(998,244,353\) 取模的结果。

思路:

我菜死了。

其实这道题可以转换为一个\(n\times m\)的矩阵,矩阵每一行最多只能选一个数,每一列可以选若干个数,询问有多少种方案满足选取的每一列的个数均不超过选取总个数的一半。

正难则反。我们发现,对于不合法的方案,仅有一列选取的个数会超过总个数的一半。

所以我们可以枚举超过总个数一半的那一列,然后设\(f[i][j][k]\)表示选取到第\(i\)行,枚举的超过一半的这一列选择了\(j\)个,其他列选择了\(k\)个的方案数。

那么这一列可以选择这一列,可以选择其他列,也可以不选。所以有方程

\[f[i][j][k]=f[i-1][j][k]+f[i-1][j-1][k]\times cnt[i][j]+f[i-1][j][k-1]\times (sum[i]-cnt[i][j])
\]

其中\(sum[i]=\sum^m_{j=1}cnt[i][j]\)

那么选取枚举的这一行超过一半,最终不合法的方案数就是

\[ans=\sum_{j>k}f[n][j][k]
\]

时间复杂度\(O(mn^3)\),这样就得到了\(84pts\)的超级足的暴力分。

然而我考场这都没写出来qwq

我们发现最终只要满足\(j>k\)就可以计算进答案,中间过程我们也只关心\(j,k\)的大小关系。

所以我们可以省去\(j,k\)那两维,设\(f[i][j]\)表示第\(i\)行,选择超过一半的这一列比其他列多选的个数为\(j\)的方案数。

那么就有方程

\[f[i][k]=f[i-1][k]+f[i-1][k-1]\times cnt[i][j]+(sum[i]-cnt[i][j])\times f[i-1][k+1]
\]

然后答案就是

\[ans=\sum^{n}_{i=1}f[n][i]
\]

这样我们就在\(O(n^2)\)的时间复杂度内求出了不合法的方案数。

总方案数很好计算,第\(i\)行有\(sum[i]\)种选择方案,再加上不选,所以总方案数就是

\[all=\Pi^{n}_{i=1}(sum[i]+1)
\]

注意还要排除全部不选的情况。所以最终答案就是\(all-ans-1\)。

时间复杂度\(O(mn^2)\)。

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll; const int N=110,M=2010,MOD=998244353;
ll ans,all,f[N][N+N],cnt[N][M],sum[N];
int n,m; int main()
{
scanf("%d%d",&n,&m);
all=1;
for (int i=1;i<=n;i++)
{
for (int j=1;j<=m;j++)
{
scanf("%lld",&cnt[i][j]);
sum[i]+=cnt[i][j];
}
all=((sum[i]+1)%MOD*all)%MOD;
}
for (int j=1;j<=m;j++)
{
f[0][N]=1;
for (int i=1;i<=n;i++)
for (int k=-n+N;k<=n+N;k++)
f[i][k]=(f[i-1][k]+f[i-1][k-1]*cnt[i][j]+(sum[i]-cnt[i][j])%MOD*f[i-1][k+1])%MOD;
for (int i=1;i<=n;i++)
ans=(ans+f[n][i+N])%MOD;
}
printf("%lld",((all-ans-1)%MOD+MOD)%MOD);
return 0;
}

【CSP-S 2019】【洛谷P5664】Emiya 家今天的饭【dp】的更多相关文章

  1. 洛谷P5664 Emiya 家今天的饭 问题分析

    首先来看一道我编的题: 安娜写宋词 题目背景 洛谷P5664 Emiya 家今天的饭[民间数据] 的简化版本. 题目描述 安娜准备去参加宋词大赛,她一共掌握 \(n\) 个 词牌名 ,并且她的宋词总共 ...

  2. 洛谷P5664 Emiya 家今天的饭 题解 动态规划

    首先来看一道题题: 安娜写宋词 题目背景 洛谷P5664 Emiya 家今天的饭[民间数据] 的简化版本. 题目描述 安娜准备去参加宋词大赛,她一共掌握 \(n\) 个 词牌名 ,并且她的宋词总共有 ...

  3. 洛谷 P5664 Emiya 家今天的饭(84分)

    题目传送门 解题思路: 对于每一个列c,f[i][j][k]表示到第i行,第c列选了j个,其它列一共选了k个,然后我们读题意发现只要j>k,那就一定是不合法的,然后统计所有方案,减去所有不合法方 ...

  4. P5664 Emiya 家今天的饭

    题面 link 前言 去年把我做自闭的一道题,看了一眼题面,发现只有 t1 有点思路,结果写到一半发现自己读错题了,又只能花时间来重构,结果后面的暴力一点都没写(主要是自己当时不会) 然后,这道题还因 ...

  5. 括号树 noip(csp??) 2019 洛谷 P5658

    洛谷AC通道 本题,题目长,但是实际想起来十分简单. 首先,对于树上的每一个后括号,我们很容易知道,他的贡献值等于上一个后括号的贡献值 + 1.(当然,前提是要有人跟他匹配,毕竟题目中要求了,是不同的 ...

  6. 格雷码 CSP(NOIP??)2019 洛谷 P5657

    洛谷AC通道! 多年过后,重新来看这道D1T1,20min不到AC,再回忆起当初考场三小时的抓耳挠腮,不禁感慨万千啊!! 发篇题解记录一下. 思路:直接dfs模拟即可(二进制找规律是不可能的, 这辈子 ...

  7. 洛谷CF809C Find a car(数位DP)

    洛谷题目传送门 通过瞪眼法发现,\(a_{i,j}=(i-1)\text{ xor }(j-1)+1\). 二维差分一下,我们只要能求\(\sum\limits_{i=0}^x\sum\limits_ ...

  8. 【题解】洛谷P1169 [ZJOI2007] 棋盘制作(坐标DP+悬线法)

    次元传送门:洛谷P1169 思路 浙江省选果然不一般 用到一个从来没有听过的算法 悬线法: 所谓悬线法 就是用一条线(长度任意)在矩阵中判断这条线能到达的最左边和最右边及这条线的长度 即可得到这个矩阵 ...

  9. 洛谷 P2015 二叉苹果树(codevs5565) 树形dp入门

    dp这一方面的题我都不是很会,所以来练(xue)习(xi),大概把这题弄懂了. 树形dp就是在原本线性上dp改成了在 '树' 这个数据结构上dp. 一般来说,树形dp利用dfs在回溯时进行更新,使用儿 ...

随机推荐

  1. 【转帖】微软全新Windows 10X细节一览

    微软全新Windows 10X细节一览 https://www.cnbeta.com/articles/tech/906241.htm windows NT之后 又一大改进 今年的Surface发布会 ...

  2. PAT(B) 1070 结绳(Java)

    题目链接:1070 结绳 (25 point(s)) 题目描述 给定一段一段的绳子,你需要把它们串成一条绳.每次串连的时候,是把两段绳子对折,再如下图所示套接在一起.这样得到的绳子又被当成是另一段绳子 ...

  3. Pair(二进制处理+数位dp)(2019牛客暑期多校训练营(第七场))

    示例: 输入: 33 4 24 5 27 8 5 输出:5 7 31 题意:存在多少对<x,y>满足x&y>C或x^y<C的条件.(0<x<=A,0< ...

  4. golang - 映射 ini 配置文件

    使用:setting.AppSetting.PageSize 包:go get github.com/go-ini/ini

  5. centos7,jdk8,tomcat8镜像推送到腾讯云

    目录 centos7 jdk tomcat centos7 创建一个mycentos7的文件 vim mycentos7 FROM centos:7 MAINTAINER qyp_mail@sohu. ...

  6. (转)AS3正则:元子符,元序列,标志,数量表达符

    (转)AS3正则:元子符,元序列,标志,数量表达符: AS3正则:元子符,元序列,标志,数量表达符 七月 4th, 2010 归类于 AS3前端技术 作者Linkjun 进行评论 as3正则:元子符, ...

  7. Selenium 配置IE浏览器

    1.安装selenium pip install selenium 2.安装IE浏览器driver http://selenium-release.storage.googleapis.com/ind ...

  8. java ArithUtil 数据计算精度工具

    ArithUtil: /** * 如果需要精确计算,非要用String来够造BigDecimal不可 */ package com.leaniot.securitymonitor.util; impo ...

  9. springboot读取系统级环境变量,和读写系统属性以及unittest来获取环境变量的方法

    环境变量的读取以及系统属性的设置 环境变量只能读取,不能修改,系统属性可以修改 系统变量的读取方式: System.getEnv() 系统属性有多重读取和修改方式: 其修改方式为: 读取系统属性: @ ...

  10. Delphi开发的数据库程序在C:\PDOXUSRS.NET生成文件,拒绝访问及读写权限

    Delphi开发的数据库程序在C:\PDOXUSRS.NET生成文件,拒绝访问及读写权限, "无法打开 PARADOX.NET.这个文件可以随便删除的,下次会自动产生. Permission ...