Description

传送门

Solution

算法1 32pts

爆搜,复杂度\(O((m+1)^n)\)

算法2 84pts

裸的dp,复杂度\(O(n^3m)\)

首先有一个显然的性质要知道:

最多只有一种主要食材出现在超过一半的主要食材里。

接下来考虑如果只有前两个限制条件的情况,那么答案就是

\[\Pi_{i=1}^{n} (sum_i+1) - 1
\]

其中\(sum_i = \sum \limits_{j=1}^m a_{i,j}\),\(+1\)是因为对于每一行只有选一道菜或者不选这些选择,\(-1\)是因为要去除一道菜都不选的情况。

对于第3个限制条件,发现直接做不太好做,考虑容斥,即用总方案数,也就是上面的式子,减去不合法的方案数。

由最开始的那个性质可以得到一个做法:

枚举不合法的那一种主要食材,然后进行\(dp\)。发现我们并不需要知道每一种主要食材具体用在了多少道菜上,只需要知道当前枚举的食材用在了多少道菜,其它的并不影响方案。那么设\(f_{i,j,k}\)表示前\(i\)中烹饪方式,选了\(j\)道菜,其中\(k\)道的主要食材是枚举的不合法食材。转移分三种情况:令\(s\)表示当前枚举的不合法食材,

  1. 不在这一种烹饪方式中进行选择:\(f_{i,j,k}=f_{i-1,j,k}\)

  2. 在这种烹饪方式中选择了合法的食材:\(f_{i,j,k}=(sum_i-a_{i,s}) \times f_{i,j-1,k}\)

  3. 在这种烹饪方式中选择了不合法的食材:\(f_{i,j,k}=a_{i,s}\times f_{i,j-1,k-1}\)

那么不合法的方案数就是

\[\sum \limits_{k\ge \lfloor \frac{j}{2} \rfloor} f_{n,j,k}
\]

code

#include <bits/stdc++.h>
using namespace std; typedef long long ll;
const ll mod = 998244353;
const int _ = 100 + 10;
const int __ = 2000 + 10;
int n, m, A[_][__];
ll sum[_], f[_][_ << 1], tmp, ans = 1; int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
scanf("%d", &A[i][j]);
sum[i] = (sum[i] + A[i][j]) % mod;
}
ans = ans * (sum[i] + 1) % mod;
}
ans = (ans - 1 + mod) % mod; for (int k = 1; k <= m; ++k) {
memset(f, 0, sizeof(f));
f[0][n] = 1;
for (int i = 1; i <= n; ++i) {
for (int j = -i + n; j <= i + n; ++j) {
f[i][j] = (f[i - 1][j] + f[i - 1][j - 1] * A[i][k] % mod + f[i - 1][j + 1] * (sum[i] - A[i][k]) % mod) % mod;
if (i == n && j > n) tmp = (tmp + f[i][j]) % mod;
}
}
} ans = (ans - tmp + mod) % mod;
printf("%lld\n", ans);
return 0;
}

算法三 100pts

考虑如何对算法二的\(dp\)进行优化,减少不必要的状态。对限制三进行转化,限制三即为

\[x\le \lfloor \frac{k}{2} \rfloor
\]

\[2x \le k
\]

\[2x - k \le 0
\]

\[x-(k-x)\le 0
\]

发现并不需要关心使用了食材的菜的具体数量,只需要关心合法与不合法的菜的差值即可,即这个差值与原来差值相同的状态的集合是对应的,那么我们就可以以此为状态进行dp,转移与上面是类似的。

唯一要注意的一点是可能出现负数,要加上一个偏移量\(n\)

  1. 不在这一种烹饪方式中进行选择:\(f_{i,j}=f_{i-1,j}\)

  2. 在这种烹饪方式中选择了合法的食材:\(f_{i,j}=(sum_i-a_{i,s}) \times f_{i,j+1}\)

  3. 在这种烹饪方式中选择了不合法的食材:\(f_{i,j}=a_{i,s}\times f_{i,j-1}\)

code

#include <bits/stdc++.h>
using namespace std; typedef long long ll;
const ll mod = 998244353;
const int _ = 100 + 10;
const int __ = 2000 + 10;
int n, m, A[_][__];
ll sum[_], f[_][_ << 1], tmp, ans = 1; int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
scanf("%d", &A[i][j]);
sum[i] = (sum[i] + A[i][j]) % mod;
}
ans = ans * (sum[i] + 1) % mod;
}
ans = (ans - 1 + mod) % mod; for (int k = 1; k <= m; ++k) {
memset(f, 0, sizeof(f));
f[0][n] = 1;
for (int i = 1; i <= n; ++i) {
for (int j = -i + n; j <= i + n; ++j) {
f[i][j] = (f[i - 1][j] + f[i - 1][j - 1] * A[i][k] % mod + f[i - 1][j + 1] * (sum[i] - A[i][k]) % mod) % mod;
if (i == n && j > n) tmp = (tmp + f[i][j]) % mod;
}
}
} ans = (ans - tmp + mod) % mod;
printf("%lld\n", ans);
return 0;
}

【CSP-S 2019】D2T1 Emiya 家今天的饭的更多相关文章

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

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

  2. 「CSP-S 2019」Emiya 家今天的饭

    description loj 3211 solution 看到题目中要求每种主要食材至多在一半的菜中被使用,容易想到补集转换. 即\(ans=\)总方案数-存在某一种食材在一半以上的菜中被使用的方案 ...

  3. [CSP-S 2019 Day2]Emiya家今天的饭

    思路: 这种题目就考我们首先想到一个性质.这题其实容易想到:超限的菜最多只有一个,再加上这题有容斥那味,就枚举超限的菜然后dp就做完了. 推式子能力还是不行,要看题解. 式子还需要一个优化,就是废除冗 ...

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

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

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

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

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

    CSP-S2 2019 D2T1 很不错的一题DP,通过这道题学到了很多. 身为一个对DP一窍不通的蒟蒻,在考场上还挣扎了1h来推式子,居然还有几次几乎推出正解,然而最后还是只能打个32分的暴搜滚粗 ...

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

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

  8. Emiya家今天的饭 NOIP2019 (CSP?) 类DP好题 luoguP5664

    luogu题目传送门! 首先,硬求可行方案数并不现实,因为不好求(去年考场就这么挂的,虽然那时候比现在更蒟). 在硬搞可行方案数不行之后,对题目要求的目标进行转换: 可行方案数 = 总方案数 - 不合 ...

  9. CSP-S 2019 Emiya 家今天的饭

    64 pts 类似 乌龟棋 的思想,由于 \(64pts\) 的 \(m <= 3\), 非常小. 我们可以设一个 \(dp\),建立 \(m\) 个维度存下每种物品选了几次: \(f[i][A ...

随机推荐

  1. 【机器学习之数学】03 有约束的非线性优化问题——拉格朗日乘子法、KKT条件、投影法

    目录 1 将有约束问题转化为无约束问题 1.1 拉格朗日法 1.1.1 KKT条件 1.1.2 拉格朗日法更新方程 1.1.3 凸优化问题下的拉格朗日法 1.2 罚函数法 2 对梯度算法进行修改,使其 ...

  2. juc-2-原子变量与CAS算法

      i++的原子性问题 例子   int i=10;           i++; 结果   i=10   分析过程                    在计算机 底层 会有生成一个临时变量 tem ...

  3. Day8 - Python基础8 异常处理、反射、单例模式

    本节内容: 1:异常处理 2:反射 3:单例模式 1.异常处理  1.异常简介 在编程过程中为了增加友好性,在程序出现bug时一般不会将错误信息显示给用户,而是现实一个提示的页面,通俗来说就是不让用户 ...

  4. 2019-2020-1 20199305《Linux内核原理与分析》第六周作业

    系统调用的三层机制(下) (一)给MenuOS增加命令 (1)打开虚拟机,首先用rm -rf menu指令删除当前的menu目录,然后用git clone重新克隆一个新版本的menu,进入menu,运 ...

  5. [HDU6288]Tree

    题目 题解 首先读题就很成问题....英语咋办呐!!! 直接考虑有点复杂,直接分析每一条边能否被选入最终答案.对于这条边,看看他的\(size[v]\) 与 \(n-size[v]\) 是否都大于等于 ...

  6. DRF--路由组件和版本控制

    路由组件 先来看下我们前面写的路由 from django.conf.urls import url, include from .views import BookModelView urlpatt ...

  7. subprocess模块(了解)

    目录 一.subprocess模块 一.subprocess模块 subprocess模块允许你去创建一个新的进程让其执行另外的程序,并与它进行通信,获取标准的输入.标准输出.标准错误以及返回码等.更 ...

  8. Win32 程序开发:窗口类结构体 WNDCLASS 和 WNDCLASSEX

    一.窗口类结构体简介 窗口类结构体包含了窗口的各种参数信息.比如:窗口的图标.菜单栏.背景颜色.窗口的消息处理等等. 窗口类结构体有两个:WNDCLASS(早期版本) 和 WNDCLASSEX(新版本 ...

  9. 【STM32H7教程】第19章 STM32H7的GPIO应用之按键FIFO

    完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第19章       STM32H7的GPIO应用之按键FIF ...

  10. tushare+pandas实现财经数据分析

    写在前面的话: 这是一个优秀的财经接口包,博主平时工作中也有使用,觉得很好,现在分享一些使用心得给需要的人,tushare并不是一个炒股软件,只是一个提供pandas数据的工具,具体如何使用,因人而异 ...