Description:

有 \(n\) 中烹饪方法和 \(m\) 种食材,要求:

  • 至少做一种菜
  • 所有菜的烹饪方法各不相同
  • 同种食材的菜的数量不能超过总菜数的一半

求做菜的方案数。

Solution1:考虑 DP

先容斥一下,答案为忽略第三个条件所得的方案数减去每一种食材超过一半的方案数之和。

忽略掉第三个条件之后答案显然是

\[\prod_{i=1}^n(1+\sum_{j=1}^m a_{i,j})-1
\]

减去 1 是去掉一道菜都不做的方案。

枚举每一列超过一半的情况,显然,除这一列外,其他 \(n-1\) 列是一样的。那么对于第 \(col\) 列,设 \(f_{i,j,k}\) 表示前 \(i\) 行,第 \(col\) 列选 \(j\) 个且其他列选 \(k\) 个的方案数。则:

\[f_{i,j,k} = f_{i-1,j,k}\text{(不选)}+a_{i,col}*f_{i-1,j-1,k}+(s_i-a_{i,col})*f_{i,-1,j,k-1}
\]

此时的复杂度是 ,\(O(m)\) 的枚举 \(col\) * \(O(n^3)\) 的 \(DP\), = \(O(mn^3)\) ,可以得到 84pts 的好成绩了

Code:

#include<bits/stdc++.h>

using namespace std;
typedef long long ll; const int N = 101;
const int M = 2001;
const int mod = 998244353;
ll n,m;
ll s[N],a[N][M],f[N][N][N];
ll ans=1; void init()
{
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
{
scanf("%lld",&a[i][j]);
s[i]=(s[i]+a[i][j])%mod;
}
ans=(ans*(s[i]+1))%mod;
}
ans=(mod-1+ans)%mod;
} int main()
{
init();
for(int col=1;col<=m;++col)
{
memset(f,0,sizeof(f));
f[0][0][0]=1;
for(int i=1;i<=n;++i)
{
for(int j=0;j<=i;++j)
{
for(int k=0;k<=i-j;++k)
{
f[i][j][k]=f[i-1][j][k]+f[i-1][j-1][k]*a[i][col]+f[i-1][j][k-1]*(s[i]-a[i][col]);
f[i][j][k]=(f[i][j][k]%mod+mod)%mod;
}
}
} for(int j=1;j<=n;++j)
{
for(int k=0;k<=n-j;++k)
{
if(k<j) ans=((ans-f[n][j][k])%mod+mod)%mod;
}
}
}
printf("%lld\n",ans);
return 0;
}

Solution2:考虑优化

然后我们发现我们并不关心j和k的具体值。我们只关心他们的差。所以我们可以把后两维压缩成一维。

设 \(f_{i,j}\) 表示前 \(i\) 行,第 \(col\) 列比其他列多选 \(j\) 个的方案数。则:

\[f_{i,j} = f_{i-1,j}\text{(不选)}+a_{i,col}*f_{i-1,j-1}+(s_i-a_{i,col})*f_{i,-1,j+1}
\]

此时的复杂度是 ,\(O(m)\) 的枚举 \(col\) * \(O(n^2)\) 的 \(DP\), = \(O(mn^2)\) ,可以得到 100pts 的好成绩了

这里有一个小技巧就是把每个j都加上n,避免数组负下标的出现。

Code:

#include<bits/stdc++.h>

using namespace std;
typedef long long ll; const int N = 101;
const int M = 2001;
const int mod = 998244353;
ll n,m;
ll s[N],a[N][M],f[N][N*2];
ll ans=1; void init()
{
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
{
scanf("%lld",&a[i][j]);
s[i]=(s[i]+a[i][j])%mod;
}
ans=(ans*(s[i]+1))%mod;
}
ans=(mod-1+ans)%mod;
} int main()
{
init();
for(int col=1;col<=m;++col)
{
memset(f,0,sizeof(f));
f[0][n]=1;
for(int i=1;i<=n;++i)
{
for(int j=n-i;j<=n+i;++j)//注意dp的范围!
{
f[i][j]=f[i-1][j]+f[i-1][j-1]*a[i][col]+f[i-1][j+1]*(s[i]-a[i][col]);
f[i][j]=(f[i][j]%mod+mod)%mod;
}
} for(int j=1;j<=n;++j)
{
ans=((ans-f[n][n+j])%mod+mod)%mod;
}
}
printf("%lld\n",ans);
return 0;
}

Question:

DP的取值范围问题还是不清楚。

CSP2019 Emiya 家今天的饭的更多相关文章

  1. CSP2019 Emiya 家今天的饭 题解

    这题在考场上只会O(n^3 m),拿了84分.. 先讲84分,考虑容斥,用总方案减去不合法方案,也就是枚举每一种食材,求用它做超过\(\lfloor \frac{k}{2} \rfloor\) 道菜的 ...

  2. csp2019 Emiya家今天的饭题解

    qwq 由于窝太菜了,实在是不会,所以在题解的帮助下过掉了这道题. 写此博客来整理一下思路 正文 传送 简化一下题意:现在有\(n\)行\(m\)列数,选\(k\)个数的合法方案需满足: 1.一行最多 ...

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

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

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

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

  5. 【NOIP/CSP2019】D2T1 Emiya 家今天的饭

    这个D2T1有点难度啊 原题: 花了我一下午的时间,作为D2T1的确反常 条件很奇怪,感觉不太直观,于是看数据范围先写了个暴力 写暴力的时候我就注意到了之前没有仔细想过的点,烹饪方式必须不同 虽然a很 ...

  6. 【CSP-S 2019】【洛谷P5664】Emiya 家今天的饭【dp】

    题目 题目链接:https://www.luogu.org/problem/P5664 Emiya 是个擅长做菜的高中生,他共掌握 \(n\) 种烹饪方法,且会使用 \(m\) 种主要食材做菜.为了方 ...

  7. 【CSP-S 2019】D2T1 Emiya 家今天的饭

    Description 传送门 Solution 算法1 32pts 爆搜,复杂度\(O((m+1)^n)\) 算法2 84pts 裸的dp,复杂度\(O(n^3m)\) 首先有一个显然的性质要知道: ...

  8. Emiya 家今天的饭

    \(dp_{i,j,k}\)表示前\(i\)种烹饪方法,假设最多的是食材\(j\),食材\(j\)比其他食材多\(k\)次出现 其中\(i \in [1,n],j \in [1,m],k \in [- ...

  9. 【JZOJ6433】【luoguP5664】【CSP-S2019】Emiya 家今天的饭

    description analysis 首先可以知道不符合要求的食材仅有一个,于是可以容斥拿总方案数减去选不合法食材的不合法方案数 枚举选取哪一个不合法食材,设\(f[i][j]\)表示到第\(i\ ...

随机推荐

  1. C语言学习建议!8年编程开发经验

    C语言是几乎所有编程语言的先驱与灵感的来源,Perl,PHP,Python和Ruby都是用它写的,同样什么Microsoft Windows,Mac OS X,还有GNU/Linu这些操作系统,都是靠 ...

  2. Fluent_Python_Part1序幕,01-data-model, 数据模型

    01-data-model/frenchdeck.py 1. Python解释器碰到特殊的句法时,会使用__特殊方法__去激活一些基本的对象操作. 特殊方法的存在是为了被解释器用的.没有my_obje ...

  3. Spring Boot 如何动态切换数据源

    本章是一个完整的 Spring Boot 动态数据源切换示例,例如主数据库使用 lionsea 从数据库 lionsea_slave1.lionsea_slave2.只需要在对应的代码上使用 Data ...

  4. Mac安装php扩展redis遇到的问题,执行phpize问题

    1.安装redis在mac OS中可以使用brew命令进行安装redis:mac OS使用brew命令安装软件安装命令:brew install redis因为我已经安装过了,这里就不在赘述.安装完之 ...

  5. Educational Codeforces Round 81 (Rated for Div. 2) - D. Same GCDs(数学)

    题目链接:Same GCDs 题意:给你两个数$a$,$m(1 \leq a < m \leq 10^{10})$,求有多少个$x$满足:$0 \leq x < m$且$gcd(a,m)= ...

  6. win server 挂载

    新建服务器角色,选择[NFS服务器]. mount -o nolock \\x.x.x.x.x.x\! z:/*链接到*/

  7. zabbix4.4安装和简要设置

    简介 Zabbix 是一个基于 WEB 界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案.它能监视各种网络参数,保证服务器系统的安全运营:并提供灵活的通知机制以让系统管理员快速定位/解决 ...

  8. Java常量/变量

    1. 常量 /* 常量:在程序运行期间,固定不变的量. 常量的分类: 1. 字符串常量:凡是用双引号引起来的部分,叫做字符串常量.例如:"abc"."Hello" ...

  9. 传奇衣服、翅膀、武器、怪物、NPC等外观代码计算方法与公式

    详细介绍humX.wil  weaponX.wil itemsX.wil dnitemsX.wil stateitemX.wil monX.wil代码计算方法   以下计算方法适用于HERO引擎和3K ...

  10. numpy中的max()函数

    1.ndarray.max([int axis]) 函数功能:求ndarray中指定维度的最大值,默认求所有值的最大值. axis=0:求各column的最大值 axis=1:求各row的最大值