【BUAA Spring Training 04】斜率优化 | 状压dp | 错排 | 分治+决策单调性优化 | 树形dp | H

第四场春训,谢谢zzh学长 qwq!
DP还有好多坑没填啊


【BUAA Spring Training 04】


Tags:斜率优化 决策单调性优化 状压dp 错排 树形dp




Problem C. 玉米地


[C] 题意

给定一个玉米地二维 01 \text{01} 01 矩阵(行列数: 1 ≤ R , C ≤ 12 1 \le R,C \le 12 1RC12), 1 \text{1} 1 表示可种, 0 \text{0} 0 表示不可种

现在要种地,只能种在可种的格子,然后种的格子之间不能有公共边(不能连着左右或上下种,可以斜对角着种)

问一共有多少种种法,对 100000000 \text{100000000} 100000000 取模。


[C] 思路

看着这范围… 果断状压dp呀。

初始化就是枚举第一行,选出合法的,dp值为1。

接下来逐行枚举,先枚举这一行合法的,再枚举上一行存在的,然后转移计数。


时间复杂度: O ( 2 2 C × R ) O(2^{2C} \times R) O(22C×R)



[C] 代码

/*
 *      If we give,
 *      all we've got,
 *      we will make it through.
 */


#include <cstdio>
#include <cstdlib>

#define GC getchar()
#define _SN(x) {char _c=GC,_v=1;for(x=0;_c<48||_c>57;_c=GC)if(_c==45)_v=-1;for(;_c>=48&&_c<=57;x=(x<<1)+(x<<3)+_c-48,_c=GC);if(_v==-1)x=-x;}
#define _SAN(a,n) {int _i=0,_n=n;for(;_i<_n;++_i)_SN(a[_i])}
#define _SA(a,l,r) {int _i=l,_r=r;for(;_i<_r;++_i)_SN(a[_i])}
#define _gS(_1, _2, _3, _sc, ...) _sc
#define sc(...) _gS(__VA_ARGS__,_SA,_SAN,_SN, ...)(__VA_ARGS__)
#define _G1(_1) ({int _1;sc(_1)_1;})
#define _G2(_1,_2) int _1,_2;sc(_1)sc(_2)
#define _G3(_1,_2,_3) int _1,_2,_3;sc(_1)sc(_2)sc(_3)
#define _gG(_1,_2,_3,_get, ...) _get
#define get(...) _gG(__VA_ARGS__,_G3,_G2,_G1, ...)(__VA_ARGS__)
#define _F0N(i,n) for(int i=0;i<(n);++i)
#define _FLR(i,l,r) for(int i=(l);i<(r);++i)
#define _gF(_1, _2, _3, _F, ...) _F
#define F(...) _gF(__VA_ARGS__,_FLR,_F0N, ...)(__VA_ARGS__)
#define _FD0(i,n) for(int i=0;i<=(n);++i)
#define _FDL(i,l,r) for(int i=(l);i<=(r);++i)
#define _gFD(_1, _2, _3, _FD, ...) _FD
#define FD(...) _gFD(__VA_ARGS__,_FDL,_FD0, ...)(__VA_ARGS__)
#define FRC(R,C) for(int r=0;r<R;++r)for(int c=0;c<C;++c)

#define IL inline
#define PC putchar
template<class T>void PRT(const T _){if(_<0){PC(45),PRT(-_);return;}if(_>=10)PRT(_/10);PC(_%10+48);}
template<class T>void UPRT(const T _){if(_>=10)UPRT(_/10);PC(_%10+48);}


typedef unsigned long bint;


const int MN = 14, MP = 1<<12|1;
const bint MOD = 100000000;


bint mask[MN], dp[MN][MP];

template <typename T>
IL void inc(T &self, const T off)
{
	if ((self+=off) >= MOD)
		self -= MOD;
}

IL bool check_self(const int r, const bint state)
{
	for (bint sta=state; sta; sta>>=1)
		if ((sta & 1) && (sta & 2))
			return false;
	return !(state & mask[r]);
}

IL bool check(const bint state, const bint pre_sta)
{
	return !(state & pre_sta);
}


int main()
{
	get(R, C)
	FRC(R, C)
		mask[r] |= !get(tp) << c;

	const bint MAX_STATE = 1u<<C;
	for (bint now=0; now<MAX_STATE; ++now)
		if (check_self(0, now))
			dp[0][now] = 1;

	F(r, 1, R)
		for (bint now=0; now<MAX_STATE; ++now)
			for (bint prev=0; prev<MAX_STATE; ++prev)
				if (dp[r-1][prev] && check_self(r, now) && check(now, prev))
					inc(dp[r][now], dp[r-1][prev]);

	bint sum = 0;
	for (bint now=0; now<MAX_STATE; ++now)
		inc(sum, dp[R-1][now]);
	UPRT(sum);

	return 0;
}




Problem A.

(待更)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值