CSP-S2 2019 D2T1

很不错的一题DP,通过这道题学到了很多。

身为一个对DP一窍不通的蒟蒻,在考场上还挣扎了1h来推式子,居然还有几次几乎推出正解,然而最后还是只能打个32分的暴搜滚粗


题意分析

给出一个矩阵,要求每行只能选一个节点,每列选的节点不能超过所有选的节点的一半,不能不选,给出每个节点的选择方案数,求总方案数

思路分析

可以看出,维护每列已选的节点复杂度太大,不太可行;因此很容易想到,先不考虑每列不超过一半的这个限制,求出总方案数,然后再减去考虑这个限制后不合法的方案数。现在问题就变成,求任意列选的节点超过所有选的节点的一半的方案数之和。

显然,在一个方案中,只可能有一列的节点超过所有选的节点的一半。因此可以想到枚举这个超过限制的列,然后对于这个列进行DP求解。

具体实现

设$f_{i,j,k}$表示前$i$行选$j$个节点,当前枚举到的列选$k$个节点的方案数。对于每个列,复杂度为$O(n^3)$,总的复杂度为$O(mn^3)$,可以得到84分的高分。

想得到满分还需要进一步优化。考虑将某两个状态合并。观察状态,实际上我们想知道的只是$j,k$的大小关系,对于具体的值并不关心,考虑将它们合并到一维。

考虑我们需要的限制条件$k>\left \lfloor \frac{j}{2} \right \rfloor$,变形一下可以得到$2k+n-j>n$。观察这个式子,可以发现,$n-j$就是这$n$行里没有选的行数。然后一个奇妙的想法就出来了,对于每个节点,选它时当做该列选了两次,而对于某一行不选时,当做所有列选了一次,最终要找的就是当前列被选超过$n$次的方案。这样就成功地优化掉了第二维。

给一下状态转移方程:

f[j][k]=(f[j][k]+f[j-1][k]*(cnt[j]-w[j][i]))%P;//不选当前列
f[j][k+1]=(f[j][k+1]+f[j-1][k])%P;//不选当前行
f[j][k+2]=(f[j][k+2]+f[j-1][k]*w[j][i])%P;//选当前行当前列对应的节点

注意取模时出现负数的情况,记得开long long。

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
const int N=200,M=3000,P=998244353;//FFT(雾
int n,m;
ll ans=1;
ll cnt[N],w[N][M],f[N][M];
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
scanf("%lld",&w[i][j]),cnt[i]=(cnt[i]+w[i][j])%P;
ans=(ans*(cnt[i]+1))%P;//计算全部答案
}
ans=(ans+P-1)%P;//减去全部不选的情况
for(int i=1;i<=m;i++)
{
memset(f,0,sizeof(f));
f[0][0]=1;//DP初值
for(int j=1;j<=n;j++)
for(int k=0;k<=2*(j-1);k++)
{
f[j][k]=(f[j][k]+f[j-1][k]*(cnt[j]-w[j][i]))%P;
f[j][k+1]=(f[j][k+1]+f[j-1][k])%P;
f[j][k+2]=(f[j][k+2]+f[j-1][k]*w[j][i])%P;
}
for(int j=n+1;j<=2*n;j++)
ans=(ans+P-f[n][j])%P;//减去当前枚举到的不合法方案
}
printf("%lld",ans);
return 0;
}

[CSP-S2019]Emiya 家今天的饭 题解的更多相关文章

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

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

  2. csp2019 Emiya家今天的饭题解

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

  3. CSP2019 Emiya 家今天的饭 题解

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

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

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

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

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

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

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

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

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

  8. P5664 Emiya 家今天的饭

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

  9. 洛谷 P5664 [CSP-S2019] Emiya 家今天的饭

    链接: P5664 题意: 给出一个 \(n*m\) 的矩阵 \(a\),选 \(k\) 个格子(\(1\leq k\leq n\)),每行最多选一个,每列最多选\(⌊\dfrac k2⌋\) 个,同 ...

随机推荐

  1. PHP date_timezone_set() 函数

    ------------恢复内容开始------------ 实例 设置 DateTime 对象的时区: <?php$date=date_create("2013-05-25" ...

  2. PHP bindec() 函数

    实例 把二进制转换为十进制: <?phpecho bindec("0011") . "<br>";echo bindec("01&q ...

  3. luogu P2183 [国家集训队]礼物

    LINK:礼物 n个物品 m个人 每个人要分得wi 个物品 每个物品互异 分给每个人的物品不分顺序 求方案数. \(n,p\leq 1e9 m\leq 5\) 方案数 那显然是 第一个人拿了w1件物品 ...

  4. 当asp.net core偶遇docker一(模型验证和Rabbitmq 二)

    上一篇我们说到构建了一个Rabbitmq容器 现在我们说说如何在一个悄悄传输消息到队列 我们现在设计一个Rabbitmq发送消息部分的模块 先设计一个远程发送的接口 public interface ...

  5. 【六省联考2017】组合数问题 题解(矩阵快速幂优化DP)

    题目链接 题目大意:求$(\sum\limits_{i=0}^n C_{nk}^{ik+r})\ mod \ p$的值. --------------------- 讲真,一开始看到这个题我都没往DP ...

  6. 使用Python从PDF文件中提取数据

    前言 数据是数据科学中任何分析的关键,大多数分析中最常用的数据集类型是存储在逗号分隔值(csv)表中的干净数据.然而,由于可移植文档格式(pdf)文件是最常用的文件格式之一,因此每个数据科学家都应该了 ...

  7. Druid数据源的使用

    1 Druid数据源简介 Druid是Java语言中最好的数据库连接池.Druid能够提供强大的监控和扩展功能.通过访问http://localhost:8080(自己的端口)/druid/ 可以查看 ...

  8. java_内部类、匿名内部类的使用

    内部类 将一个类A定义在另一个类B里面,里面的那个类A就称为内部类,B则称为外部类. 内部类的分类 成员内部类,类定义在了成员位置 (类中方法外称为成员位置) 局部内部类,类定义在方法内 成员内部类 ...

  9. JavaScript小游戏实例:简单的键盘练习

    键盘是一种常用的输入设备,灵活熟练地使用键盘进行输入是计算机用户需掌握的一门基本功.下面我们编写一个简单的键盘练习游戏. 1.刺破气泡交互式小动画 在编写简单的键盘练习游戏之前,先设计一个简单地刺破气 ...

  10. 论文结果图:matplotlib和seaborn实现

    在论文中,可视化结果往往很重要,毕竟文字太抽象,需要图片向审稿人直观的展现出我们的结果.我也写了俩篇论文和一篇专利的申请,其中也有一些画图的程序,因此记录,防止以后忘了.由于篇幅原因,文章就不贴代码, ...