「ZJOI2009」多米诺骨牌

题目描述
有一个n × m 的矩形表格,其中有一些位置有障碍。现在要在这个表格内 放一些1 × 2 或者2 × 1 的多米诺骨牌,使得任何两个多米诺骨牌没有重叠部分,任何一个骨牌不能放到障碍上。并且满足任何相邻两行之间都有至少一个骨牌横跨,任何相邻两列之间也都至少有一个骨牌横跨。求有多少种不同的放 置方法,注意你并不需要放满所有没有障碍的格子。\(n, m \leq 15\)

解题思路 :

先考虑没有至少一个骨牌横跨这个限制该怎么做,只需要轮廓线 \(\text{dp}\) 记录一下轮廓线上的格子有没有放每次分讨缺口进行转移即可。如果只有行有限制也比较好做,只需要轮廓线的时候再多记一维来钦定必须要横跨即可,或者枚举哪些列没有横跨,可以通过二项式反演(容斥)得到答案。

于是根据上面两个思路口胡了一个非常 \(\text{Naive}\) 的做法并且成功狗带了,最初的做法每次预处理出每一个子矩阵行必须要跨过的答案,暴力枚举哪些列不跨过容斥。错误的地方在于可能有一个子矩阵并不需要马上让行被跨过,可以在枚举的同一行的另外一个子矩阵被跨过。

这里挂掉后就发现不得不对行列都进行容斥了,考虑暴力容斥的复杂度是 \(O(4^nn^2)\) 显然不能过。但是观察发现一旦行确定好了,列的分割线怎么枚举关于行的贡献都不会变,所以可以暴力枚举行再额外用一个 \(\text{dp}\) 维护列的贡献。显然系数只于选的列的数量有关,可以得到转移方程 \(dp[i] = \sum_{j<i} -dp[j] \times calc(j+1, i, s)\) 。其中 \(calc(j+1, i, s)\) 表示 \([j+1, i]\) 这一块被当前枚举的行集合 \(s\) 划分后的总方案数,这里可以通过轮廓线 \(\text{dp}\) 预处理出每一块子矩阵任意放的方案数来计算,复杂度 \(O(n)\) 。所以用 \(\text{dp}\) 维护后复杂度变成了 \(O(2^n n^2)\) ,足以通过此题。

​其实本题主要的复杂度瓶颈是在预处理部分,由于障碍的存在,不得不预处理出 \(pre[x1][x2][y1][y2]\) 表示这个子矩阵不考虑限制的摆放方案,由于一次轮廓线 \(\text{dp}\) 可以通过 \(O(2^nn^2)\) 的复杂度算出以一条横着的扫描线向下推出的所有子矩阵的值。直接看的话复杂度是 \(O(2^nn^5)\) ,但是观察发现对于每一行的横着的扫描线,每一种长度要算的都是 \(O(n)\) 级别的,而 \(\sum_{i=1}^n2^i = 2^{n+1} - 1\) ,所以实际上一行枚举的集合大小之和只有 \(2^{n+1}\) ,总复杂度就是 \(O(n^32^{n+1})\) ,当然也可以直接暴力出奇迹

/*program by mangoyang*/
#pragma GCC optimize("Ofast","inline","-ffast-math")
#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){int f = 0, ch = 0; x = 0;for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;if(f) x = -x;
}
#define Rint register int
const int N = 16, S = (1 << 15) + 5, mod = 19901013;
char mp[N][N];
int f[2][N][S], pre[N][N][N][N], dp[N], val[N], ans, n, m;
inline void up(int &x, int y){ x += y; if(x >= mod) x -= mod; }
inline void gao(int w, int h, int x, int y){for(Rint o = 0; o < 2; o++) for(Rint i = 0; i <= h; i++)for(Rint s = 0; s < (1 << h); s++) f[o][i][s] = 0;f[0][h][(1<<h)-1] = 1;for(Rint i = 1, o = 1; i <= w; i++, o ^= 1){for(Rint s = 0; s < (1 << h); s++) f[o][0][s] = f[o^1][h][s];  for(Rint j = 0; j <= h; j++)for(Rint s = 0; s < (1 << h); s++) f[o^1][j][s] = 0;for(Rint j = 0; j < h; j++) for(Rint s = 0; s < (1 << h); s++){if(mp[i+x-1][j+y] == 'x'){up(f[o][j+1][s|(1<<j)], f[o][j][s]); continue;}if(!((1 << j) & s)) up(f[o][j+1][s|(1<<j)], f[o][j][s]);if(j && (!((1 << j - 1) & s)))up(f[o][j+1][s|(1<<j-1)|(1<<j)], f[o][j][s]);up(f[o][j+1][s&(~(1<<j))], f[o][j][s]);}for(Rint s = 0; s < (1 << h); s++) up(pre[x][i+x-1][y][h+y-1], f[o][h][s]);}
}
inline int calc(int x, int y, int s){int ls = 0, res = 1;for(int i = 0; i < n - 1; i++) if((1 << i) & s)res = 1ll * res * pre[ls+1][i+1][x][y] % mod, ls = i + 1;res = 1ll * res * pre[ls+1][n][x][y] % mod;return res;
}
inline void addvalue(int s){memset(dp, 0, sizeof(dp)), dp[0] = -1;for(int i = 1; i <= m; i++) for(int j = 0; j < i; j++) up(dp[i], (1ll * -dp[j] * calc(j + 1, i, s) % mod + mod) % mod);up(ans, (__builtin_popcount(s) & 1 ? -1 : 1) * dp[m]);
}
signed main(){read(n), read(m);for(int i = 1; i <= n; i++) scanf("%s", mp[i] + 1);for(int i = 1; i <= n; i++)for(int j = 1; j <= m; j++)for(int k = j; k <= m; k++) gao(n - i + 1, k - j + 1, i, j);for(int i = 0; i < (1 << n - 1); i++) addvalue(i);cout << (ans % mod + mod) % mod;return 0;
}

转载于:https://www.cnblogs.com/mangoyang/p/9896757.html

「ZJOI2009」多米诺骨牌相关推荐

  1. 【每日一题】 1128. 等价多米诺骨牌对的数量

    [每日一题] 1128. 等价多米诺骨牌对的数量 避免每日太过咸鱼,一天搞定一道LeetCode算法题 一.题目描述 给你一个由一些多米诺骨牌组成的列表 dominoes. 如果其中某一张多米诺骨牌可 ...

  2. Blender多米诺骨牌动画学习教程 The Impossible Domino Run in Blender

    流派:电子学习| MP4 |视频:h264,1280×720 |音频:AAC,48.0 KHz 语言:英语+中英文字幕(根据原英文字幕机译更准确)|大小:8.53 GB 含课程文件 |时长:8h 20 ...

  3. S6 edge+的多米诺骨牌效应:大屏的趋势

    日前,为庆祝三星S6 edge+国行版的顺利发售,三星盖乐世社区的一些粉丝自发组织了三星疯狂"盖星人"第一期活动--活动现场除了可以对S6 edge+进行全方面体验之外,还将演示著 ...

  4. P1282 多米诺骨牌 (差值DP+背包)

    题目描述 多米诺骨牌有上下2个方块组成,每个方块中有1~6个点.现有排成行的 上方块中点数之和记为S1,下方块中点数之和记为S2,它们的差为|S1-S2|.例如在图8-1中,S1=6+1+1+1=9, ...

  5. P1282-多米诺骨牌【dp,背包】

    正题 评测记录:https://www.luogu.org/recordnew/lists?uid=52918&pid=P1282 题目大意 n个多米诺骨牌,上下值不相同,可以交换一个多米诺上 ...

  6. 【动态规划】 多米诺骨牌 (ssl 1632/luogu 1282)

    多米诺骨牌多米诺骨牌多米诺骨牌 Description Input 输入文件的第一行是一个正整数n(1≤n≤1000),表示多米诺骨牌数.接下来的n行表示n个多米诺骨牌的点数.每行有两个用空格隔开的正 ...

  7. 【01背包】洛谷P1282多米诺骨牌

    题目描述 多米诺骨牌有上下2个方块组成,每个方块中有1~6个点.现有排成行的 上方块中点数之和记为S1,下方块中点数之和记为S2,它们的差为|S1-S2|.例如在图8-1中,S1=6+1+1+1=9, ...

  8. 多米诺骨牌v.1MEL语言

    // //  //Script Name:多米诺骨牌v.1 //Author:疯狂小猪  //Last Updated: 2011.10.5 //Email:wzybwj@163.com //  // ...

  9. leetcode 1128. 等价多米诺骨牌对的数量

    给你一个由一些多米诺骨牌组成的列表 dominoes. 如果其中某一张多米诺骨牌可以通过旋转 0 度或 180 度得到另一张多米诺骨牌,我们就认为这两张牌是等价的. 形式上,dominoes[i] = ...

最新文章

  1. 开源云联盟耿航:中国开源软件的发展趋势
  2. [ZJOI2011]细胞——斐波那契数列+矩阵加速+dp
  3. USB Kill v2.0,一个可以瞬间烧毁电脑或平板的“U盘”
  4. cxLookupComboBox使用方法
  5. js laypage mysql_layui中的分页laypage
  6. Designing Virtual Connect for vSphere 5.x
  7. linux内核全局变量同名,Linux系统下DSO同名全局变量浅析
  8. elasticsearch docker无法挂载_ElasticSearch数据备份与恢复
  9. Hibernate中createCriteria即QBC查询的详细用法 .Hibernate中createCriteria即QBC查询的详细用法 ....
  10. java 排序 1和1_160308、java排序(形如1.1、1.2.1)
  11. matlab求雷克子波相位谱,求雷克子波的振幅谱和相位谱的MATLAB程序,谢谢 !!!!!...
  12. Java SE、Java EE、Java ME三者之间的区别
  13. wps如何只让他显示3级标题_怎么设置一二三级标题
  14. 对结构体数组进行冒泡排序(根据名字大小)
  15. 【论文翻译】Clustering by fast search and find of density peaks
  16. Rust:error[E0468]: an `extern crate` loading macros must be at the crate root 处理方法
  17. 异构网络互联;路由与转发;SDN基本概念;拥塞控制
  18. 一对同居男女同一天的日记
  19. 噪声特性及matlab函数
  20. 什么是python自动化测试?

热门文章

  1. 世界上最值钱的初创公司
  2. ps插件 Ultimate Retouch Panel AEX for mac破解版
  3. 1ppi等于多少dpi_Android开发之显示篇(弄懂ppi、dpi、pt、px、dp、dip、sp之间的关系只需这一篇)...
  4. 普元的ajax,有人了解普元 primeton EOS 产品的么?可否评价一下?
  5. android夜景录像模式,【图片】三种夜景拍摄手法优缺点对比,仅供参考【android吧】_百度贴吧...
  6. 再生龙备份linux文件多大,使用再生龙Clonezilla备份还原Linux系统
  7. linux上的两种可执行程序
  8. Notepad++添加读取十六进制插件HexEditor
  9. 华为云mysql认证ssl_华为云SSL证书
  10. 【牛腩新闻发布系统之handler】