hdu5729思维~~~

相当棒的一道题,主要是注意一些性质:

1.所有小正方形的边长都相等那么很明显这是一个平行四边形。菱行

2.平行具有传递性,也就是说如果某两条边垂直,那么那些平行的边也相互垂直!!!这是此题关键

3.我们的目标是所有小正方形的边一直保持垂直。

4.如果你此前做过关于二分图的一些题的话(网格题一般都会有二分图~~~~)你就会发现此题就是求联通图的数目,直接dp就好了

>_<mod写错,导致debug好久~~~~

写联通图dp的关键就是你拿一个点出来,然后进行讨论。。网上很多教程的。。。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll mod = 1000000007;
double kk = 1e-12;
ll c[11][11], cut[11][11], link[11][11],fact[110];
void init()
{
	fact[0] = 1;
	for (int i = 1; i <= 105; i++)
		fact[i] = fact[i - 1] * 3,
		fact[i] %= mod;
	for (int i = 0; i <= 10; i++)
	{
		cut[0][i] = 1; cut[i][0] = 1;
		link[0][i] = 0; link[i][0] = 0;
	}
	cut[1][1] = 1; link[1][1] = 2;
	c[0][0] = 1;
	for (int i = 1; i <= 10; i++)
	{
		c[i][0] = 1; c[i][i] = 1;
	}
	for (int i = 2; i <= 10; i++)
		for (int j = 1; j <= i-1; j++)
		{
		c[i][j] = c[i - 1][j] + c[i - 1][j - 1];
		}
}
void solve()
{
	init();
	for (int i = 1; i <= 10; i++)
	{
		for (int j = 1; j <= 10; j++)
		{
			if (i == 1 && j == 1)
				continue;
			cut[i][j] += cut[i - 1][j] + link[i - 1][j];
			cut[i][j] %= mod;
			for (int k = 0; k <= i - 1; k++)
			{
				for (int q = 1; q <= j; q++)
				{
					if (1 + k + q == i + j)continue;
					ll num1 = c[i - 1][k]; ll num2 = c[j][q];
					int l1 = k + 1; int r1 = q;
					int l2 = i - 1 - k; int r2 = j - q;
					cut[i][j] += num1*num2 % mod*link[l1][r1]%mod* ((link[l2][r2] + cut[l2][r2]) % mod);
						cut[i][j] %= mod;
				}
			}
			ll all = fact[i*j];
			link[i][j] = all - cut[i][j];
			link[i][j] = (link[i][j] + mod) % mod;
		}
	}
}
int main()
{
	solve();
	int n, m;
	while (scanf("%d%d", &n, &m)!=EOF)
	{
		printf("%lld\n", link[n][m]);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值