HDU 5729 Rigid Frameworks(连通性DP)

【题目链接】 http://acm.hdu.edu.cn/showproblem.php?pid=5729

【题目大意】

  给出一个n*m的方格框,可以在单位矩形中添加两种对角线的线,使得其变得稳定,问使得其变成稳定图形的方案数。

【题解】

  稳定状态指的是在n*m范围内每行每列都有一个固定的格子,并且联动,计算合法的情况非常的复杂,难以枚举,因此我们可以枚举非法情况,从组合数中减去即可。非法情况即将图形划分为合法部分和非法部分,注意枚举全面。

【代码】

#include <cstdio>
using namespace std;
#define rep(i,n) for(int i=1;i<=n;i++)
const long long mod=1e9+7;
long long dp[15][15][105],c[105][105];
int n,m;
long long pow(long long a,long long b){
    long long tmp=1; a%=mod;
    while(b){
        if(b&1)tmp=tmp*a%mod;
        a=a*a%mod;
        b>>=1;
    }return tmp;
}
int main(){
    rep(i,100){
        c[i][0]=c[i][i]=1;
        rep(j,i-1)c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
    }c[0][0]=dp[1][0][0]=dp[0][1][0]=1;
    rep(i,10)rep(j,10){
        if(i==1||j==1){dp[i][j][i+j-1]=1;continue;}
        rep(k,i*j){
            dp[i][j][k]=c[i*j][k];
            rep(ii,i)for(int jj=0;jj<=j;jj++){
                if(i+j==ii+jj)continue;
                for(int kk=0;kk<=k;kk++){
                    long long tmp=c[i-1][ii-1]*c[j][jj]%mod;
                    tmp=tmp*dp[ii][jj][kk]%mod;
                    tmp=tmp*c[(i-ii)*(j-jj)][k-kk]%mod;
                    dp[i][j][k]=(dp[i][j][k]+mod-tmp)%mod;
                }
            }
        }
    }while(~scanf("%d%d",&n,&m)){
        long long ans=0;
        rep(i,n*m)ans=(ans+pow(2,i)*dp[n][m][i]%mod)%mod;
        printf("%lld\n",ans);
    }return 0;
}

  

时间: 2024-10-06 05:41:44

HDU 5729 Rigid Frameworks(连通性DP)的相关文章

HDU 5729 Rigid Frameworks

目前还是不能彻底理解这题......http://blog.csdn.net/dpppbr/article/details/51972196 #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<map> #include<set> #include<queue> #inc

HDU 5729 Rigid Frameworks (联通块计数问题)

题目传送门 通过看题解画图可以发现: 不论怎么转,一列里的横边/一行里的竖边始终平行 当我们加固一个格子时,会让它所在的这一行的竖边和这一列的横边保证垂直 而我们的目标是求所有竖边和横边都保证垂直的方案数 把一行里的所有竖边看成一个点,把一列里的所有横边看成一个点.一共$n+m$个点 把图看成二分图,左侧$n$个点,右侧$m$个点.加固一个格子相当于在左侧的一个点和右侧的一个点之间连边! 我们的问题变成了求解二分图的连通图个数! 接下来就是很套路的$DP$了 定义$f(a,b)$表示左边$a$个

hdu 3555 Bomb(数位dp)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3555 题目大意:就是给你一个数n,判断从0到n有多少个数含有数字49...... 是不是觉得跟hdu2089很相似呀... 思路:跟hdu2089一样的,注意给出的数比较大,所以这儿用__int64  .... code: #include<cstdio> #include<iostream> #include<cstring> #include<algorithm&

HDU 1231 最大连续子序列 DP题解

典型的DP题目,增加一个额外要求,输出子序列的开始和结尾的数值. 增加一个记录方法,nothing special. 记录最终ans的时候,同时记录开始和结尾下标: 更新当前最大值sum的时候,更新开始节点. const int MAX_N = 10001; long long arr[MAX_N]; int N, sta, end; long long getMaxSubs() { long long sum = 0, ans = LLONG_MIN; int ts = 0; for (int

[ACM] hdu 2089 不要62(数位Dp)

不要62 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 19043    Accepted Submission(s): 6442 Problem Description 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer). 杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就

HDU 4901 The Romantic Hero(DP)

HDU 4901 The Romantic Hero 题目链接 题意:给定一个序列,要求找一个分界点,然后左边选一些数异或和,和右边选一些数且和相等,问有几种方法 思路:dp,从左往右和从右往左dp,求出异或和且的个数,然后找一个分界点,使得一边必须在分界点上,一边随意,然后根据乘法原理和加法原理计算 代码: #include <cstdio> #include <cstring> typedef __int64 ll; const int N = 1024; const int

HDU 1160 FatMouse&#39;s Speed DP题解

本题就先排序老鼠的重量,然后查找老鼠的速度的最长递增子序列,不过因为需要按原来的标号输出,故此需要使用struct把三个信息打包起来. 查找最长递增子序列使用动态规划法,基本的一维动态规划法了. 记录路径:只需要记录后继标号,就可以逐个输出了. #include <stdio.h> #include <algorithm> using namespace std; const int MAX_N = 1005; struct MouseSpeed { int id, w, s; b

HDU 2089 不要62(数位DP,三种姿势)

HDU 2089 不要62(数位DP,三种姿势) ACM 题目地址:HDU 2089 题意: 中文题意,不解释. 分析: 100w的数据,暴力打表能过 先初始化dp数组,表示前i位的三种情况,再进行推算 直接dfs,一遍搜一变记录,可能有不饥渴的全部算和饥渴的部分算情况,记录只能记录全部算(推荐看∑大的详细题解Orz) 代码: 1. 暴力 (以前写的) /* * Author: illuz <iilluzen[at]gmail.com> * File: 2089_bf.cpp * Create

HDU 2084 数塔 --- 入门DP

HDU 2084 数塔 从下往上递推,状态转移方程 dp[i][j] = max( dp[i+1][j], dp[i+1][j+1]) + a[i][j]; /* HDU 2084 数塔 --- 入门DP */ #include <cstdio> const int N = 105; int dp[N][N]; int MAX(int a, int b){ return a > b ? a : b; } int main() { #ifdef _LOCAL freopen("D