Online JudgeHdu5155

Label:思维题+容斥,计数Dp

题面:

题目描述

给定一个大小为\(N*M\)的神奇盒子,里面每行每列都至少有一个钻石,问可行的排列方案数。由于答案较大,输出对\(1e9+7\)取模后的结果。

输入

多组数据。每组数据读入两个整数\(N,M\)

\(0≤N,M≤50\)

输出

每组数据输出一行表示答案。

样例

Input

1 1
2 2
2 3

Output

1
7
25

Hint

There are 7 possible arrangements for the second test case.

They are:

11

11

11

10

11

01

10

11

01

11

01

10

10

01

Assume that a grids is '1' when it contains a jewel otherwise not.

题解

1.做法一(计数Dp)

定义状态\(dp[i][j]\)表示已经摆放好了前i行(前面i行都合法,即每行都放了至少一个钻石),并且有j列上已经摆放了至少一个钻石。答案很明显是\(dp[n][m]\)。

转移到第\(i\)行时,

1、枚举当前准备在第i行放的钻石个数\(k\)

2、其中有\(z\)个摆在了之前没有钻石的列上(也就是说这z个钻石给哪些之前没有钻石的列做出贡献)

3、再枚举一个之前已经有钻石的列数\(j\)(\(j∈[k-z,m-z]\))

关于j的范围:下限,既然有z个摆在了之前没有钻石的列上,那就有\(k-z\)个放在有钻石的列上。上限,除了那\(z\)列没放钻石,其他\(m-z\)列已经放了。

则有\(dp[i][j+t]+=dp[i-1][j]*当前行方案数\)。当前行的方案数由两部分组成:一是要将这\(z\)个钻石放在之前没有钻石的列上——\(c[m-j][z]\);二是要将剩余的\(k-z\)个钻石放在之前已经有钻石的列上——\(c[j][m-z]\)。根据乘法原理,两者相乘即可。

综上,该算法时间复杂度为\(O(N^2+case*N^4)\)。(\(N^2\)为前面组合数的预处理)。

#include<bits/stdc++.h>
#define For(a,b,c) for(register int a=b;a<=c;++a)
#define mod 1000000007
using namespace std;
int n,m;
long long dp[55][55],c[55][55];
void pre(){
c[0][0]=1;
for(int i=1;i<=50;i++)c[i][0]=c[i][i]=1;
for(int i=2;i<=50;i++){
for(int j=1;j<i;j++)c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
}
}
int main(){
pre();
while(~scanf("%d%d",&n,&m)){
memset(dp,0,sizeof(dp));
For(i,1,m)dp[1][i]=c[m][i];
For(i,2,n)For(k,1,m)For(z,0,k)For(j,k-z,m-z){
dp[i][j+z]+=dp[i-1][j]*c[j][k-z]%mod*c[m-j][z]%mod;
dp[i][j+z]%=mod;
}
printf("%lld\n",dp[n][m]);
}
}

2.做法二(容斥)

这种做法就比较优秀了。

题目是让我们求每一行每一列都至少有一个钻石的方案数,也即求,有0列一颗钻石都没有、其他列随意的方案数(前提是每一行都至少有一个钻石——这样才能保证行这一维上也合法,这一点我们可以在后面人为控制)。

有0列不太好求,将其转化成至少有0列然后再通过容斥进行去重。

定义\(f(i)\)表示填完整个盒子后,至少有\(i\)列一个钻石都没有、其他列随意,的方案数。

  • 为什么"至少"这个问法比较可做,原因在于我们可以人为地选定m列中的i列,强制让这几列一个钻石都不放,剩余的随意即可——如果改成"有”,我们还得人为控制剩下的m-i列,情况就变得复杂了。

很容易得出\(f(i)=C(m,i)*每一行的摆列方案数^n\),至于每一类的摆列方案数,如果没有限制的话就是\(2^{m-i}\)了,但是之前说了,我们还得保证行上至少有一个钻石,所以去掉全是0(这一行不放钻石)的这种情况。所以最后$$f(i)=C(m,i)*(2{m-i}-1)n$$

最后根据容斥原理\(ans=f(0)-f(1)+f(2)-f(3)+...f(m)\)。

总的时间复杂度为\(O(N^2+case*MlogN)\)。

//下面其实可以预处理2的幂的
#include<bits/stdc++.h>
#define For(a,b,c) for(register int a=b;a<=c;++a)
#define mod 1000000007
using namespace std;
typedef long long ll;
int n,m;
ll c[55][55];
void pre(){
c[0][0]=1;
for(int i=1;i<=50;i++)c[i][0]=c[i][i]=1;
for(int i=2;i<=50;i++){
for(int j=1;j<i;j++)c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
}
}
ll ksm(ll r,int d){
ll res=1;
while(d){
if(d&1)res=res*r%mod;
r=r*r%mod;d>>=1;
}
return res;
}
int main(){
pre();
while(~scanf("%d%d",&n,&m)){
ll ans=0;
for(int i=0;i<=m;i++){
//从m中选择i列永远不放钻石,剩余的情况随意安排
ll val=c[m][i]*ksm(ksm(2,m-i)-1,n)%mod;
if(i%2==0)ans=(ans+val)%mod;
else ans=(ans-val+mod)%mod;
}
printf("%lld\n",ans%mod);
}
}

update20191024

这道题的\(n,m\)开的比较小,只有\(50\),所以上面两个做法都直接\(N^2\)预处理组合数了,但显然的,可以不用预处理组合数,可以直接\(O(NlogN)\)预处理出阶乘,模逆元(带个log是快速幂的),这样利用容斥就可以在\(O(MlogN)\)的时间内解决此问题,\(n,m\)可以开到\(3000\)左右。

[Hdu-5155] Harry And Magic Box[思维题+容斥,计数Dp]的更多相关文章

  1. HDU 5155 Harry And Magic Box --DP

    题意:nxm的棋盘,要求每行每列至少放一个棋子的方法数. 解法:首先可以明确是DP,这种行和列的DP很多时候都要一行一行的推过去,即至少枚举此行和前一行. dp[i][j]表示前 i 行有 j 列都有 ...

  2. hdu 1796 How many integers can you find 容斥第一题

    How many integers can you find Time Limit: 12000/5000 MS (Java/Others)    Memory Limit: 65536/32768 ...

  3. 题解报告:hdu 1028 Ignatius and the Princess III(母函数or计数DP)

    Problem Description "Well, it seems the first problem is too easy. I will let you know how fool ...

  4. hdu 4135 [a,b]中n互质数个数+容斥

    http://acm.hdu.edu.cn/showproblem.php?pid=4135 给定一个数n,求某个区间[a,b]内有多少数与这个数互质. 对于一个给定的区间,我们如果能够求出这个区间内 ...

  5. HDU - 4059: The Boss on Mars (容斥 拉格朗日 小小的优化搜索)

    pro: T次询问,每次给出N(N<1e8),求所有Σi^4 (i<=N,且gcd(i,N)==1) ; sol:  因为N比较小,我们可以求出素因子,然后容斥.  主要问题就是求1到P的 ...

  6. HDU 5122 K.Bro Sorting(模拟——思维题详解)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5122 Problem Description Matt's friend K.Bro is an A ...

  7. [HDOJ 5155] Harry And Magic Box

    题目链接:HDOJ - 5155 题目大意 有一个 n * m 的棋盘,已知每行每列都至少有一个棋子,求可能有多少种不同的棋子分布情况.答案对一个大素数取模. 题目分析 算法1: 使用容斥原理与递推. ...

  8. 【HDOJ】5155 Harry And Magic Box

    DP.dp[i][j]可以表示i行j列满足要求的组合个数,考虑dp[i-1][k]满足条件,那么第i行的那k列可以为任意排列(2^k),其余的j-k列必须全为1,因此dp[i][j] += dp[i- ...

  9. HDU 6205 2017沈阳网络赛 思维题

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6205 题意:给你n堆牌,原本每一堆的所有牌(a[i]张)默认向下,每次从第一堆开始,将固定个数的牌(b ...

随机推荐

  1. C++ 系列:函数可变长参数

    一.基础部分 1.1 什么是可变长参数 可变长参数:顾名思义,就是函数的参数长度(数量)是可变的.比如 C 语言的 printf 系列的(格式化输入输出等)函数,都是参数可变的.下面是 printf ...

  2. virtualbox manager命令小记

    virtualbox 控制虚拟机 VBoxManage list runningvms 列出运行的虚拟机 (返回名称和UUID): VBoxManage list runningvms Stop ru ...

  3. jquery实现文字由下到上循环滚动的实例代码

    <div id="oDiv"> <ul id="oUl"> <li>第1个li元素</li> <li> ...

  4. Vim: 强大的g

    来源于:http://vim.wikia.com/wiki/Power_of_g 一般格式: :[range]g/pattern/cmd 对range内所有符合pattern的行执行cmd 常见的一些 ...

  5. 「题解」:$d$

    问题 A: $d$ 时间限制: 1 Sec  内存限制: 512 MB 题面 题面谢绝公开. 题解 赛时切掉了然而过程十分曲折. 贪心思路很好想.然而一开始错误以为是单峰.其实几个峰都有可能. 开场写 ...

  6. E: Sub-process /usr/bin/dpkg returned an error code (1)解决办法

    解决方法: 先将info文件夹更名 sudo mv /var/lib/dpkg/info /var/lib/dpkg/info.bk 新建一个新的info文件夹 sudo mkdir /var/lib ...

  7. 怎样配置duilib

    duilib是一个免费的界面库,它可利用xml文件自定义界面元素,并且可以在商业项目中无偿使用.怎样在VS中配置duilib界面库呢?请看下面的介绍. 工具/原料 duilib 下载和编译duilib ...

  8. 云-腾讯云-短信:短信(SMS)

    ylbtech-云-腾讯云-短信:短信(SMS) 快速稳定.简单易用.触达全球的短信服务,支持国内短信.语音短信与国际短信 1.返回顶部 1. 腾讯云短信 SMS 简介 腾讯云短信(Short Mes ...

  9. Error parsing XML: junk after document element这样的错误 - CSDN博客

    很多开发者可能在编写XML布局文件时提示Error parsing XML: junk after document element这样的错误,这里Android123提示大家一般合法的XML文件只有 ...

  10. openstack实战部署

    简介:Openstack系统是由几个关键服务组成,他们可以单独安装,这些服务根据你的云需求工作在一起,这些服务包括计算服务.认证服务.网络服务.镜像服务.块存储服务.对象存储服务.计量服务.编排服务和 ...