题面传送门

本来说要找道轮廓线 \(dp\) 的题目刷刷来着的?然后就找到了这道题。

然鹅这个题给我最大的启发反而不在轮廓线 \(dp\),而在于让我新学会了一个玩意儿叫做 Min-Max 容斥。

Min-Max 容斥大概讲的就是这样一件事情:对于任意集合 \(S\),\(\max(S)=\sum\limits_{T\subseteq S,T\ne\varnothing}(-1)^{|T|-1}\min(T)\),因为这个式子包含容斥系数 \((-1)^{|T|-1}\) 和集合的 \(\min,\max\),因此被称为 Min-Max 容斥。

证明还算容易,假设 \(S\) 中的元素从小到大依次为 \(a_1,a_2,\cdots,a_n\),考虑每个 \(a_i\) 作为最小值出现的贡献,显然 \(a_n\) 的贡献就是 \(a_n\),因为它只能在 \(T=\{a_n\}\) 中作为最小值,而对于 \(i<n\),\(a_i\) 为 \(T\) 的最小值当且仅当 \(T\) 可以写成 \(\{a_i\}\cup T'\) 的形式,其中 \(T'\subseteq\{a_{i+1},a_{i+2},\cdots,a_n\}\),考虑枚举 \(T'\) 的大小 \(s\),那么共有 \(\dbinom{n-i}{s}\) 个可选的 \(T'\),它们的贡献均为 \((-1)^s\),故总贡献为 \(\sum\limits_{i=0}^{n-i}\dbinom{n-i}{s}(-1)^s=0^{n-i}=0\),故总贡献就是 \(a_n=\max(S)\)。

接下来考虑怎样将 Min-Max 容斥使用到这道题上,我们考虑将所有 * 格子编个号,记 \(t_i\) 为编号为 \(i\) 的 * 格第一次被覆盖的时间,那么题目要求的值即为 \(E(\max\{t_i\})\),我们知道对于这样的集合,\(\max\) 是不太好求的,不过 \(E(\min\{t_i\})\) 非常好求,记 \(C\) 为有多少个 \(1\times 2\) 的矩形包含至少一个 * 格,\(D\) 为总共有多少个 \(1\times 2\) 的矩形(显然 \(D=n(m-1)+m(n-1)\)),那么 \(E(\min\{t_i\})=\dfrac{C}{D}\)。因此考虑套用 Min-Max 容斥,记 \(S\) 为 \(t_i\) 组成的集合所有,那么 \(E(\max(S))=\sum\limits_{T\subseteq S}(-1)^{T-1}E(\min(T))\)。直接枚举子集显然是不行的,不过我们发现 \(E(\min\{t_i\})\) 的表达式中,\(D\) 为定值,而 \(C\) 的范围也不会太大,最多不过 \(1200\),因此我们考虑转而枚举 \(C\) 并预处理所有子集 \(T\) 满足其对应的 \(C\) 为我们枚举的值的贡献之和。这东西怎么预处理呢?就要用到我们一开始说的轮廓线 \(dp\) 了,记 \(dp_{i,j,k,l}\) 为考虑了前 \(i\) 列,第 \(i\) 列考虑到了第 \(j\) 行,轮廓线左侧取/不取的状态为 \(k\),有 \(l\) 个 \(1\times 2\) 的矩形包含了至少一个 \(T\) 中的格子的所有子集 \(T\) 的 \((-1)^{|T|-1}\) 之和。搞清楚状态之后转移应该就比较容易了,具体见代码罢。

时间复杂度 \(n^2m^22^n\)。

最后总结一个小 trick,碰到那种形如求 \(E(\max(S))\) 的题目,如果 \(E(\min(S))\) 比较容易求得,那么可以考虑 Min-Max 容斥。

const int MAXN=6;
const int MAXM=100;
const int MAXP=64;
const int MAXCNT=1200;
const int MOD=998244353;
void inc(int &x,int y){((x+=y)>=MOD)&&(x-=MOD);}
int n,m,inv[MAXCNT+5];char s[MAXN+5][MAXM+5];
int dp[MAXM+5][MAXN+5][MAXP+5][MAXCNT+5];
int main(){
scanf("%d%d",&n,&m);int cnt=n*(m-1)+m*(n-1);inv[1]=1;
for(int i=2;i<=cnt;i++) inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
for(int i=1;i<=n;i++) scanf("%s",s[i]+1);
dp[1][1][0][0]=1;if(s[1][1]=='*') dp[1][1][1][0]=MOD-1;
for(int i=1;i<=m;i++) for(int j=1;j<=n;j++)
for(int k=0;k<(1<<n);k++) for(int l=0;l<=cnt;l++){
if(i==m&&j==n) continue;
if(!dp[i][j][k][l]) continue;
int ni=(j==n)?i+1:i,nj=j%n+1,add=0;
if(s[nj][ni]=='*')
inc(dp[ni][nj][k|(1<<nj-1)][l+(ni!=1)+(nj!=1)],MOD-dp[i][j][k][l]);
if((k>>j-1&1)&&(nj!=1)) add++;
if((k>>nj-1&1)) add++;
inc(dp[ni][nj][k&(~(1<<nj-1))][l+add],dp[i][j][k][l]);
}
int ans=0;
for(int i=1;i<=cnt;i++) for(int j=0;j<(1<<n);j++)
ans=(ans+1ll*dp[m][n][j][i]*inv[i]%MOD*cnt)%MOD;
printf("%d\n",MOD-ans);
return 0;
}

UOJ 422 - 【集训队作业2018】小Z的礼物(Min-Max 容斥+轮廓线 dp)的更多相关文章

  1. UOJ 422 [集训队作业2018] 小Z的礼物 min-max容斥 期望 轮廓线dp

    LINK:小Z的礼物 太精髓了 我重学了一遍min-max容斥 重写了一遍按位或才写这道题的. 还是期望多少时间可以全部集齐. 相当于求出 \(E(max(S))\)表示最后一个出现的期望时间. 根据 ...

  2. [UOJ422][集训队作业2018]小Z的礼物——轮廓线DP+min-max容斥

    题目链接: [集训队作业2018]小Z的礼物 题目要求的就是最后一个喜欢的物品的期望得到时间. 根据$min-max$容斥可以知道$E(max(S))=\sum\limits_{T\subseteq ...

  3. uoj#422. 【集训队作业2018】小Z的礼物(MIn-Max容斥+插头dp)

    题面 传送门 题解 好迷-- 很明显它让我们求的是\(Max(S)\),我们用\(Min-Max\)容斥,因为\(Min(S)\)是很好求的,只要用方案数除以总方案数算出概率,再求出倒数就是期望了 然 ...

  4. 【UOJ#422】【集训队作业2018】小Z的礼物(min-max容斥,轮廓线dp)

    [UOJ#422][集训队作业2018]小Z的礼物(min-max容斥,轮廓线dp) 题面 UOJ 题解 毒瘤xzy,怎么能搬这种题当做WC模拟题QwQ 一开始开错题了,根本就不会做. 后来发现是每次 ...

  5. UOJ 449 【集训队作业2018】喂鸽子 【生成函数,min-max容斥】

    这是第100篇博客,所以肯定是要水过去的. 首先看到这种形式的东西首先min-max容斥一波,设\(f_{c,s}\)表示在\(c\)只咕咕中,经过\(s\)秒之后并没有喂饱任何一只的概率. \[ \ ...

  6. [集训队作业2018]蜀道难——TopTree+贪心+树链剖分+链分治+树形DP

    题目链接: [集训队作业2018]蜀道难 题目大意:给出一棵$n$个节点的树,要求给每个点赋一个$1\sim n$之内的权值使所有点的权值是$1\sim n$的一个排列,定义一条边的权值为两端点权值差 ...

  7. uoj #450[集训队作业2018]复读机

    传送门 \(d=1\),那么任何时刻都可以\(k\)个复读机的一种,答案为\(k^n\) \(d>1\),可以枚举某个复读机的复读次数(必须是\(d\)的倍数),然后第\(i\)个复读时间为\( ...

  8. UOJ#422. 【集训队作业2018】小Z的礼物

    #422. [集训队作业2018]小Z的礼物 min-max容斥 转化为每个集合最早被染色的期望时间 如果有x个选择可以染色,那么期望时间就是((n-1)*m+(m-1)*n))/x 但是x会变,中途 ...

  9. 2019.2.25 模拟赛T1【集训队作业2018】小Z的礼物

    T1: [集训队作业2018]小Z的礼物 我们发现我们要求的是覆盖所有集合里的元素的期望时间. 设\(t_{i,j}\)表示第一次覆盖第i行第j列的格子的时间,我们要求的是\(max\{ALL\}\) ...

随机推荐

  1. kafka应用讲解及应用场景(三)

    一. 验证 1.进入bin目录 cd bin 2.ls查看脚本 会发现下面有很多脚本文件,由于我是要创建一个topic所有直接打开kafka-topics.sh脚本查看命令 打开脚本后发现里面有很多命 ...

  2. vue2和vue3比较

    一.vue3新特性: 1.数据响应重新实现(ES6的proxy代替Es5的Object.defineProperty) 2.源码使用ts重写,更好的类型推导 3.虚拟DOM新算法(更快,更小) 4.提 ...

  3. LeetCode:堆专题

    堆专题 参考了力扣加加对与堆专题的讲解,刷了些 leetcode 题,在此做一些记录,不然没几天就忘光光了 力扣加加-堆专题(上) 力扣加加-堆专题(下) 总结 优先队列 // 1.java中有优先队 ...

  4. Scrum Meeting 0427

    零.说明 日期:2021-4-27 任务:简要汇报两日内已完成任务,计划后两日完成任务 一.进度情况 组员 负责 两日内已完成的任务 后两日计划完成的任务 qsy PM&前端 完成部分登录,注 ...

  5. 热身训练1 ping ping ping

    点此进入 题意: 一棵树,n+1 个节点,以0号节点为根,给出端点(a,b),节点a到节点b的路径上,至少有一个点是"坏掉的",求"坏掉的点"最少 分析: St ...

  6. 单片机I/O口推挽与开漏输出详解(力荐)

    推挽输出:可以输出高,低电平,连接数字器件;推挽结构一般是指两个三极管分别受两互补信号的控制,总是在一个三极管导通的时候另一个截止. 开漏输出:输出端相当于三极管的集电极. 要得到高电平状态需要上拉电 ...

  7. Linux多线程编程之详细分析

    线程?为什么有了进程还需要线程呢,他们有什么区别?使用线程有什么优势呢?还有多线程编程的一些细节问题,如线程之间怎样同步.互斥,这些东西将在本文中介绍.我见到这样一道面试题: 是否熟悉POSIX多线程 ...

  8. 图像原始格式(YUV444 YUV422 YUV420)一探究竟

    前段时间搞x264编码测试,传参的时候需要告诉编码器我的原始数据格式是什么,其中在x264.h头文件中定义了如下一堆类型. /* Colorspace type */ #define X264_CSP ...

  9. PWN学习之栈溢出

    目录 PWN学习之栈溢出 前言 写bug bug.cpp源码 OD动态调试bug.exe OD调试观察溢出 栈溢出攻击之突破密码验证 x64位栈溢出 PWN学习之栈溢出 前言 我记得我在最开始学编程的 ...

  10. Go语言核心36讲(Go语言进阶技术十二)--学习笔记

    18 | if语句.for语句和switch语句 现在,让我们暂时走下神坛,回归民间.我今天要讲的if语句.for语句和switch语句都属于 Go 语言的基本流程控制语句.它们的语法看起来很朴素,但 ...