【TCO 2013】Litpanels

2B LitPanels

Description

一个   的棋盘,选择两个   的矩形(可以相交),在矩形内任意染黑格子,问最后棋盘状态的方案数。

不妨先把结果分类。对答案的状态用一个   的包围盒包裹住,分别讨论   包围盒的方案数。
考虑我们需要满足什么条件。
1、包围盒的每一条边都必须有至少一个染色点。
2、能用两个   的矩形包裹所有染色点。
将第二个条件转化一下,考虑到矩形的两种摆放方式,变为:有两种区域,至少有一种内部没有染色点。
那么,我们总共就有6个需要考虑的条件。
枚举每一个点,统计出它在那几个条件上。
这样,我们能得到   个不同的满足情况的条件的点数。
考虑用DP统计合法方案。  表示考虑到了   种点,当前满足情况为   的方案数。
转移: .  -------  以上来自picks。

我的做法:

分别讨论 

 包围盒的方案数。只需让四个边界都又被选的点,枚举顶点状态,即可直接求出。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define Rep(i, x, y) for (int i = x; i <= y; i ++)
#define Dwn(i, x, y) for (int i = x; i >= y; i --)
#define RepE(i, x) for(int i = pos[x]; i; i = g[i].nex)
using namespace std;
typedef long long LL;
const int N = 45, mod = 1000000007;
class LitPanels {
public:
	LL sd[N * N], ans; int Sx, Sy;
	LL sqr(LL x) { return x * x % mod; }
	LL sqz(LL x) { return x * (x-1) % mod; }
	LL Find (int x, int y) { // return 0;
		int lx = min(2 * Sx, x), ly = min(2 * Sy, y);
		if (x == 1 || y == 1) {
			if (x + y <= 2) return 1;
			return sd[lx + ly - 3];
		}
		int sq = lx * ly, sq2 = sq - 2*(lx+ly) + 4;
		LL k1 = sd[lx - 2], k2 = sd[ly - 2], ret = 0;
		(ret += ((sqr(k1) * sqr(k2) % mod) * sd[sq2] % mod) * 7) %= mod;  // 4 T
		(ret += (sd[sq2] * sqz(k2) % mod) * sqr(k1) * 2) %= mod; // 2 T
		(ret += (sd[sq2] * sqr(k2) % mod) * sqz(k1) * 2) %= mod; // 2 T
		(ret += (sd[sq2] * sqz(k2) % mod) * sqz(k1) * 4) %= mod; // 
		(ret += (sqr(k1 - 1) * sqr(k2 - 1) % mod) * sd[sq2]) %= mod;
		return ret;
	}
	LL Calc(int x, int y, int lx, int ly) {
		int sq = (x - 2) * ly + (y - 2) * lx - lx * ly;
		LL k1 = sd[lx] - 1, k2 = sd[ly] - 1;
		return (sqr(k1) * sqr(k2) % mod) * sd[sq] % mod;
	}
	int countPatterns(int n, int m, int sx, int sy) {
		Sx = sx, Sy = sy;
		sd[0] = 1;
		for (int i = 1; i <= n * m; i ++) sd[i] = sd[i - 1] * 2 % mod;
		Rep(i, 1, n) {
			Rep(j, 1, m) {
				LL ret = 0;
				if (i <= sx || j <= sy) ret = Find(i, j);
				else { // continue ;
					int l1 = max(0, sx * 2 - i), l2 = max(0, sy * 2 - j), sq;
					sq = 2 * sx * sy - l1 * l2;
					LL k1 = sd[sx - 1], k2 = sd[sy - 1], sq2 = sq - (sx+sy) * 2 + 2;
					(ret += (sqr(k1 - 1) * sqr(k2 - 1) % mod) * sd[sq2]) %= mod; // 都不选
					ret += sd[sq - 2]; // choose both
					(ret += (sqz(k1) * sqz(k2) % mod) * sd[sq2] * 2) %= mod; // choose one
					ret = ret * 2 % mod;
					ret = (ret - Calc(i, j, l1, l2) + mod) % mod;
				}
				(ans += ret * (n - i + 1) * (m - j + 1)) %= mod;
			}
		}
		return int((ans + 1) % mod);
	}
};



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值