题目

题目链接: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. [转帖]比特币本质其实是UTXO

    比特币本质其实是UTXO https://www.jianshu.com/p/7071e68c5262 其实并没有什么比特币,我们在交易所里或者钱包里显示的比特币余额其实是UTXO.那到底什么是UTX ...

  2. Kafka Schema Registry | 学习Avro Schema

    1.目标 在这个Kafka Schema Registry教程中,我们将了解Schema Registry是什么以及为什么我们应该将它与Apache Kafka一起使用.此外,我们将看到Avro架构演 ...

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

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

  4. 【LEETCODE】51、数组分类,简单级别,题目:581,830,1010,665

    package y2019.Algorithm.array; /** * @ClassName FindUnsortedSubarray * @Description TODO 581. Shorte ...

  5. OAuth2实现原理

    现在开放平台非常流行,例如微信开放平台.微博开放平台等,开放平台都涉及用户授权问题,OAuth2就是目前的主流授权解决方案 OAuth2是什么 OAuth(Open Authorization,开放授 ...

  6. Spark 系列(二)—— Spark开发环境搭建

    一.安装Spark 1.1 下载并解压 官方下载地址:http://spark.apache.org/downloads.html ,选择 Spark 版本和对应的 Hadoop 版本后再下载: 解压 ...

  7. Expanded, SingleChildScrollView, CustomScrollView, container, height, width

    SingleChildScrollView, CustomScrollView, container, init: double.inifinity. then use Expanded to con ...

  8. windows下安装hexo和生成博客

    首先在电脑上安装node和git,这个只要在相关官网的下载然后一步安装即可. 然后在你的电脑上新建一个文件夹,用来存放你的博客文件,比如创建hexo 进入该文件,右键打开git bash 安装hexo ...

  9. jupyter安装出现问题:安装后无法打开

    jupyter安装出现问题:安装后无法打开 traitlets.traitlets.TraitError: Could not decode 'C:\Users\\xce\xa2\xcc\xf0\xd ...

  10. input里面的提示文字修改(placeholder里的文字修改,el-input也适用)

    input::-webkit-input-placeholder { /* WebKit browsers */ color: red; } input:-moz-placeholder { /* M ...