NOIP2019 Emiya家今天的饭

ACM退役选手远程口胡
csf如今真的是太菜了,最后16分的做法愣是想了一下午
考虑使用容斥方法:

1

采用动态规划,先求出在无限制情况下,安排kkk种烹饪方法总的方案数.
记dp2[i][j]dp2[i][j]dp2[i][j]表示已经考虑完前iii种烹饪方法,共做了jjj个菜的方案数.
那么显然,决策分2种情况,用或不用第iii种烹饪方法,用的话就只能选一种主要食材.
dp2[i][j]=dp2[i−1][j]+dp2[i−1][j−1]∗(∑t=1ma[i][t])dp2[i][j]=dp2[i-1][j] + dp2[i-1][j-1]*(\sum_{t=1}^m a[i][t])dp2[i][j]=dp2[i−1][j]+dp2[i−1][j−1]∗(∑t=1m​a[i][t])
时间复杂度O(n2)O(n^2)O(n2),∑t=1ma[i][t]\sum_{t=1}^m a[i][t]∑t=1m​a[i][t]可以提前维护好.

2

采用动态规划,计算出那些不合法的方案,并将这些方案减掉.
因为每次只能有一个主要食材不合法.所以对每个主要食材单独考虑,假设当前ttt食材不合法了.
最朴素的想法是,采用dp1[i][j][k]dp1[i][j][k]dp1[i][j][k]表示考虑完前iii种烹饪方法,已经做了jjj个菜,使用ttt食材的有kkk个的方案数.

那么,决策就是第iii中烹饪方案选不选,选了之后,选不选ttt作为食材,一共333个转移.

记录linesum[i]=∑t=1ma[i][t]linesum[i]=\sum_{t=1}^m a[i][t]linesum[i]=∑t=1m​a[i][t]

dp1[i][j][k]=dp1[i−1][j][k]+dp1[i−1][j−1][k−1]∗a[i][t]+dp1[i−1][j−1][k]∗(linesum[i]−a[i][t])dp1[i][j][k]=dp1[i-1][j][k]+dp1[i-1][j-1][k-1]*a[i][t]+dp1[i-1][j-1][k]*(linesum[i]-a[i][t])dp1[i][j][k]=dp1[i−1][j][k]+dp1[i−1][j−1][k−1]∗a[i][t]+dp1[i−1][j−1][k]∗(linesum[i]−a[i][t])

最后答案减去dp1[n][j][k]∣k>j/2dp1[n][j][k]|_{k \gt j/2}dp1[n][j][k]∣k>j/2​

时间复杂度为O(n3m)O(n^3m)O(n3m),只能过84分,接下来继续优化

事实上,我们无需同时记录jjj和kkk,而只需要记录k−(j−k)k - (j-k)k−(j−k)的值就足够了,也就是ttt食材的数量和非ttt食材的数量.

这样的话,记录dp1[i][Δ]dp1[i][\Delta]dp1[i][Δ]表示考虑完前iii行,选取的ttt食材和非ttt食材的差值为Δ\DeltaΔ时候,方案数.
转移方程如下
dp1[i][Δ]=dp1[i−1][Δ]+dp1[i−1][Δ−1]∗a[i][t]+dp1[i−1][Δ+1]∗(linesum[i]−a[i][t])dp1[i][\Delta]=dp1[i-1][\Delta] + dp1[i-1][\Delta-1]*a[i][t]+dp1[i-1][\Delta+1]*(linesum[i]-a[i][t])dp1[i][Δ]=dp1[i−1][Δ]+dp1[i−1][Δ−1]∗a[i][t]+dp1[i−1][Δ+1]∗(linesum[i]−a[i][t])
最后答案减去dp1[n][Δ]∣Δ>0dp1[n][\Delta]|_{\Delta>0}dp1[n][Δ]∣Δ>0​
时间复杂度O(n2m)O(n^2m)O(n2m)

综上,总的时间复杂度O(n2m)O(n^2m)O(n2m)

AC代码

#include <iostream>
#include <cstring>
using namespace std;
#define int long long
const int MOD = 998244353;
const int maxn = 107,maxm = 2007;
int dp1[maxn][2*maxn]; //
int dp2[maxn][maxn];
int linesum[maxn]; //s1表示
int a[maxn][maxm];
int n, m;
signed main() {cin >> n >> m;for(int i = 1;i <= n;++i) {for(int j = 1;j <= m;++j) {cin >> a[i][j];a[i][j] %= MOD;linesum[i] = ( linesum[i] + a[i][j] ) % MOD;}}int ans = 0;for(int t = 1;t <= m;++t) {memset(dp1,0,sizeof(dp1));dp1[0][0 + 100] = 1;for(int i = 1;i <= n;++i) {for(int j = -i + 100;j <= i + 100;++j) {dp1[i][j] = dp1[i-1][j];dp1[i][j] += (dp1[i-1][j-1] * a[i][t]) % MOD;//取dp1[i][j] += (dp1[i-1][j+1] * ((linesum[i] - a[i][t] + MOD) % MOD)) % MOD;//不取dp1[i][j] %= MOD;}}for(int j = 1;j <= n;++j) {ans = (ans - dp1[n][j + 100]) % MOD;}}dp2[0][0] = 1;for(int i = 1;i <= n;++i) {for(int j = 0;j <= i;++j) {dp2[i][j] = dp2[i-1][j];for(int k = 1;k <= m;++k) {dp2[i][j] += dp2[i-1][j-1] * a[i][k] % MOD;dp2[i][j] %= MOD;}}}for(int j = 1;j <= n;++j)ans = (ans + dp2[n][j]) % MOD;cout << ans << endl;return 0;
}

NOIP2019 Emiya家今天的饭相关推荐

  1. 【CSP-S2019】D2T1 Emiya 家今天的饭

    CSP-S2019 D2T1 Emiya 家今天的饭 题目 题目描述 Emiya 是个擅长做菜的高中生,他共掌握 nnn 种烹饪方法,且会使用 mmm 种主要食材做菜.为了方便叙述,我们对烹饪方法从 ...

  2. [CSP day2T1]Emiya 家今天的饭

    Emiya 家今天的饭 题解 挺容易的一道dp,我们可以先考虑容斥.先加上不考虑菜数不超过一半的值,再减去超过一半的部分. 表示在前i种中选j个菜的总种类,这个dp很好想, 下面就是最重要的了. 表示 ...

  3. 2019CSP-S Day2T1 Emiya 家今天的饭 题解

    2019CSP-S Day2T1 Emiya 家今天的饭 题解 题目链接 我太菜了 64pts,m<=3m <= 3m<=3. 前64pts数据规模都差不多,因为mmm很小,考虑类似 ...

  4. Emiya家今天的饭

    题目来源: Emiya家的饭 代码 #include <bits/stdc++.h> using namespace std; const int MOD = 998244353; con ...

  5. CSP-S2019学习笔记:Emiya家今天的饭

    题目名称看样子灵感来自于日本动画片"卫宫家今天的饭". 这道题的难度是"提高+/省选-",算是提高组里比较难的.数据范围分的很细,解题方法跟数据范围关系比较大. ...

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

    太难惹!!! 文章目录 题目描述 一.分析 二.代码 总结 题目描述 Emiya 是个擅长做菜的高中生,他共掌握 n 种烹饪方法,且会使用 m 种主要食材做菜.为了方便叙述,我们对烹饪方法从 1∼n ...

  7. 洛谷P5664 Emiya 家今天的饭

    题目描述 Emiya 是个擅长做菜的高中生,他共掌握 nn 种烹饪方法,且会使用 mm 种主要食材做菜.为了方便叙述,我们对烹饪方法从 1 \sim n1∼n 编号,对主要食材从 1 \sim m1∼ ...

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

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

  9. Emiya 家今天的饭(CSP 2019 D2 T1)

    题目 题目描述 Emiya 是个擅长做菜的高中生,他共掌握 nn 种烹饪方法,且会使用 mm 种主要食材做菜.为了方便叙述,我们对烹饪方法从 1 \sim n1∼n 编号,对主要食材从 1 \sim ...

最新文章

  1. [九度][何海涛] 数组中出现次数超过一半的数字
  2. js高级---js运行原理
  3. 003_SpringBoot整合Filter
  4. PHP源码分析-数组
  5. 探测服务器操作系统,探测服务器操作系统工具
  6. react 改变css样式_web前端入门到实战:编写CSS代码的8个策略,资深开发工程师总结...
  7. Linux下MongoDB安装和配置详解
  8. ubuntu 是基于debian gnu/linux,在 Ubuntu 或其它 GNU/Linux 系统下安装 Debian
  9. 3从控制台输入三个数,并输出最大值
  10. JS 获取宽,高(ie未测)
  11. Atitit if else 选择决策流程ast对比 sql java 表达式类型 binaryExpression hase left and rit expr 目录 1.1. Sql 1
  12. MySQLl数据量不一样,导致走不同的索引
  13. natapp做一个内网穿透
  14. 转载:KOF97简易出招原理解析
  15. 计算机主机后面的usb哪个不可接入,电脑的USB接口不能使用了怎么回事?主板usb接口全部失灵的解决方法...
  16. 微软MSBI零基础从数据仓库到商业智能实战(SSIS SSAS SSRS)
  17. 基于Springboot拦截器的AES报文解密
  18. mdict.cn的安卓安装包不能找到mdx文件问题解决方法
  19. 爱情四十三课,热战与冷战
  20. 敏捷守破离:20%-200%-1200%的改善

热门文章

  1. .gpg 进程 linux,小知识之Linux系统中的最大进程数,最大文件描述,最大线程数...
  2. leetcode115. 不同的子序列
  3. [C++STL]常用查找算法
  4. Zookeeper实践与应用- Canal
  5. Redis数据结构以及对应存储策略
  6. 520 钻石争霸赛 7-5 大勾股定理 (数学)
  7. char *与char []
  8. 快速排序 (Quick Sort)(Java实现)
  9. P3835 【模板】可持久化平衡树
  10. P4127 [AHOI2009]同类分布 数位dp + 对状态剪枝