原文链接https://www.cnblogs.com/zhouzhendong/p/51Nod1518.html

题目传送门 - 51Nod1518

题意

51Nod真是个好OJ ,题意概括的真好,有助于博主偷懒不写题意概括。给51Nod 点赞!

题解

  首先,我们忽略那个“稳定”的要求,求方案数。

  显然是一个插头dp裸题,我们可以在 $O(n^2\cdot 2^n)$ 的时间复杂度中求出所有长宽的矩形区域的覆盖方案数。

  然后我们考虑容斥原理,奇加偶减。首先,枚举哪些相邻行之间有一条不穿过骨牌的直线,然后,用一个 $O(n)$ DP 来解决相邻列之间分割线的容斥。

  总的时间复杂度 $O(n^22^n)$ 。打出表之后,询问 $O(1)$ 。

代码

看着那些运行效率榜上15MS的代码我于是交了一份 0MS 的代码。正常的代码在这份代码之后。

#include <bits/stdc++.h>
int n,m,ans[17][17]={
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,6,0,108,0,1182,0,10338,0,79818,0,570342},
{0,0,0,0,0,6,0,124,62,1646,1630,18120,25654,180288,317338,1684956,3416994},
{0,0,0,0,0,0,124,0,13514,0,765182,0,32046702,0,136189727,0,378354090},
{0,0,0,0,0,108,62,13514,25506,991186,3103578,57718190,238225406,965022920,388537910,937145938,315565230},
{0,0,0,0,0,0,1646,0,991186,0,262834138,0,462717719,0,560132342,0,699538539},
{0,0,0,0,0,1182,1630,765182,3103578,262834138,759280991,264577134,712492587,886997066,577689269,510014880,807555438},
{0,0,0,0,0,0,18120,0,57718190,0,264577134,0,759141342,0,567660301,0,47051173},
{0,0,0,0,0,10338,25654,32046702,238225406,462717719,712492587,759141342,398579168,83006813,821419653,942235780,558077885},
{0,0,0,0,0,0,180288,0,965022920,0,886997066,0,83006813,0,690415372,0,620388364},
{0,0,0,0,0,79818,317338,136189727,388537910,560132342,577689269,567660301,821419653,690415372,796514774,696587391,175421667},
{0,0,0,0,0,0,1684956,0,937145938,0,510014880,0,942235780,0,696587391,0,856463275},
{0,0,0,0,0,570342,3416994,378354090,315565230,699538539,807555438,47051173,558077885,620388364,175421667,856463275,341279366}
};
int main(){
while (~scanf("%d%d",&n,&m))
printf("%d\n",ans[n][m]);
return 0;
}

  

正常的代码

#include <bits/stdc++.h>
using namespace std;
int read(){
int x=0;
char ch=getchar();
while (!isdigit(ch))
ch=getchar();
while (isdigit(ch))
x=(x<<1)+(x<<3)+ch-48,ch=getchar();
return x;
}
const int N=17,S=1<<16,mod=1e9+7;
int n,m,dp[2][S],tot[N][N],ans[N][N];
int gbit(int v,int d){
return (v>>(d-1))&1;
}
void Solve_tot(int n,int m){
memset(dp,0,sizeof dp);
int T0=1,T1=0;
dp[T1][(1<<m)-1]=1;
for (int i=1;i<=n;i++){
for (int j=1;j<=m;j++){
T0^=1,T1^=1;
memset(dp[T1],0,sizeof dp[T1]);
for (int s=0;s<(1<<m);s++){
int v=dp[T0][s];
if (!v)
continue;
dp[T1][s^(1<<(j-1))]=(dp[T1][s^(1<<(j-1))]+v)%mod;
if (j>1&&!gbit(s,j-1)&&gbit(s,j)){
int _s=s^(1<<(j-2));
dp[T1][_s]=(dp[T1][_s]+v)%mod;
}
}
}
tot[i][m]=dp[T1][(1<<m)-1];
}
}
void Get_tot(int n){
for (int m=1;m<=16;m++)
Solve_tot(n,m);
}
int GetV(int n,int s,int len){
int v=1;
for (int i=1,j;i<=n;i=j){
for (j=i;j<n&&!((s>>j)&1);j++);
j++;
v=1LL*v*tot[j-i][len]%mod;
}
return v;
}
int cnt_1(int v){
int ans=0;
while (v)
ans+=v&1,v>>=1;
return ans;
}
void Solve_ans(int n,int m){
int dp[N],v[N];
for (int s=0;s<(1<<n);s++){
if (!(s&1))
continue;
memset(dp,0,sizeof dp);
for (int i=1;i<=m;i++)
v[i]=GetV(n,s,i);
dp[0]=1;
for (int i=1;i<=m;i++)
for (int j=0;j<i;j++)
dp[i]=(-1LL*dp[j]*v[i-j]+dp[i])%mod;
int f=(cnt_1(s)&1)?-1:1;
for (int i=1;i<=m;i++)
ans[n][i]=(ans[n][i]+f*dp[i])%mod;
}
}
void Get_ans(int m){
memset(ans,0,sizeof ans);
for (int n=1;n<=16;n++)
Solve_ans(n,m);
for (int i=1;i<=m;i++)
for (int j=1;j<=m;j++)
ans[i][j]=(ans[i][j]+mod)%mod;
}
int main(){
Get_tot(16);
Get_ans(16);
while (~scanf("%d%d",&n,&m))
printf("%d\n",ans[n][m]);
return 0;
}

  

51Nod1518 稳定多米诺覆盖 动态规划 插头dp 容斥原理的更多相关文章

  1. 【做题】51NOD1518 稳定多米诺覆盖——容斥&dp

    题意:求有多少种方案,用多米诺骨牌覆盖一个\(n\times m\)的棋盘,满足任意一对相邻行和列都至少有一个骨牌横跨.对\(10^9+7\)取模. \(n,m \leq 16\) 首先,这个问题的约 ...

  2. 51nod 1518 稳定多米诺覆盖(容斥+二项式反演+状压dp)

    [传送门[(http://www.51nod.com/Challenge/Problem.html#!#problemId=1518) 解题思路 直接算不好算,考虑容斥,但并不能把行和列一起加进去容斥 ...

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

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

  4. bzoj1814: Ural 1519 Formula 1 动态规划 插头dp

    http://acm.timus.ru/problem.aspx?space=1&num=1519 题目描述 一个 m * n 的棋盘,有的格子存在障碍,求经过所有非障碍格子的哈密顿回路个数. ...

  5. 洛谷P1282 多米诺骨牌【线性dp】

    题目:https://www.luogu.org/problemnew/show/P1282 题意: 给定n个牌,每个牌有一个上点数和下点数.可以通过旋转改变交换上下点数. 问使得上点数之和和下点数之 ...

  6. ACM - 动态规划 - P1282 多米诺骨牌

    多米诺骨牌由上下 \(2\) 个方块组成,每个方块中有 \(1 \sim 6\) 个点.现有排成行的上方块中点数之和记为 \(S_1\),下方块中点数之和记为 \(S_2\),它们的差为 \(\lef ...

  7. 用1 x 2的多米诺骨牌填满M x N矩形的方案数(完美覆盖)

    题意 用 $1 \times 2$ 的多米诺骨牌填满 $M \times N$ 的矩形有多少种方案,$M \leq 5,N < 2^{31}$,输出答案模 $p$. 分析 当 $M=3$时,假设 ...

  8. Luogu P2595 [ZJOI2009]多米诺骨牌 容斥,枚举,插头dp,轮廓线dp

    真的是个好(毒)题(瘤).其中枚举的思想尤其值得借鉴. \(40pts\):插头\(dp\),记录插头的同时记录每一列的连接状况,复杂度\(O(N*M*2^{n + m} )\). \(100pts\ ...

  9. [CareerCup] 6.2 Dominos on Chess Board 棋盘上的多米诺

    6.2 There is an 8x8 chess board in which two diagonally opposite corners have been cut off. You are ...

随机推荐

  1. FreeSWITCH 增删模组

    今天在尝试FreeSWITCH新功能时,遇到一个问题,就是该功能所需要的模组没有加载,导致写了好久的代码不能看到效果,让人很是忧伤啊! 再此,将FS模组增删的方法记录下,以方便遇到同样问题的童鞋. 具 ...

  2. HDU 5288 OO’s Sequence

    题意: 给你一个序列, 有一个函数 F(L,R) 其中 ai 均不能 被 aL - aR整除的  函数值是这个ai个数 思路 : 反过来求 满足这样的条件的 ai 的区间,然后求和 #include& ...

  3. 【原创】大叔问题定位分享(33)beeline连接presto报错

    hive2.3.4 presto0.215 使用hive2.3.4的beeline连接presto报错 $ beeline -d com.facebook.presto.jdbc.PrestoDriv ...

  4. [正则表达式]匹配Unicode

    一.PHP[PCRE]之Unicode PCRE支持的16进制字符编码转义符有 \x00-\xFF,或\x{num},num为任意位16进制数 但并不支持\u0000-\uFFFF这的形式 PCRE运 ...

  5. 深度解析SpringMvc实现原理手写SpringMvc框架

    http://www.toutiao.com/a6340568603607171329/?tt_from=mobile_qq&utm_campaign=client_share&app ...

  6. Linux 操作系统死机故障处理方法总结

    通常在出现系统崩溃后,大家会担心再次出现故障,但是发现系统各日志中并没有记录到任何死机前后的信息,无法分析故障原因,认为已经无药可救.但是,实际上,Linux 有多种机制来保证发生系统崩溃后,可以获取 ...

  7. Bootstrap如何配合字体自适应

    Bootstrap框架中,字体不会自适应,及时使用rem都不行,那么就只有使用媒体查询来做.这样可能会有点麻烦,但是这是我目前找到的一个方法直接上代码了 div { font-size: 12px; ...

  8. CSS margin合并

    外边距合并 块的顶部外边距和底部外边距有时被组合(折叠)为单个外边距,其大小是组合到其中的最大外边距 发生外边距合并的三种基本情况 1. 相邻的兄弟姐妹元素 <div id="marg ...

  9. VUE开发请求本地数据的配置,旧版本dev-server.js,新版本webpack.dev.conf.js

    VUE开发请求本地数据的配置,早期的vue-lic下面有dev-server.js和dev-client.js两文件,请求本地数据在dev-server.js里配置,最新的vue-webpack-te ...

  10. 1705: 小明在工作(zzuli)

    题目描述 小明的工作是负责记录饭堂中正在排队的人的信息 在他的工作中会有三种可能的事件发生:     1.编号为id的学生加入到队伍的最后面     2.排在最前面的学生打完饭离开了队伍     3. ...