【題解】UVA11270 Tiling Dominoes

UVA11270 Tiling Dominoes

\(\text{Soluton:}\)

經典輪廓線 \(dp\) 題目。

定義:我們進行逐格 \(dp,\) 設當前在格子 \((i,j),\) 那麼輪廓線就是當前這個位置之前的同行格子和這個格子往右的上一行的同行格子的狀態。

\(f[i][j][k]\) 表示在格子 \((i,j),\) 放置完輪廓線是 \(k\) 的方案數。考慮轉移:

如果要豎着放,那麼首先要滿足當前行不是第一行,然後還要滿足它上面那個格子沒有被佔據。也就是判斷 k&(1<<(pos-1))=1 是否成立。如果不成立那就 必須 豎着放,否則這個棋盤就不會被覆蓋完整了。

再考慮不放。那首先它上面的格子不能是空的,這也是唯一的限制條件。

再考慮橫着放。先滿足它上面的格子是空的,然後還要滿足它不是左邊界並且左邊格子沒有被覆蓋。也就是 k&(1<<(pos-1))=1,k&(1<<(pos-2))=0,pos>1

於是方程也就好寫了,注意更新好輪廓線。

又可以發現,每次轉移只從上一個格子對應的狀態轉移過來,所以只需要滾動數組兩位即可。複雜度大概是 \(O(T\times n\times m\times 2^{\min\{n,m\}})\)

#include <bits/stdc++.h>
using namespace std;
typedef double db;
#define int long long
#define fi first
#define se second
#define mk make_pair
#define pb emplace_back
#define poly vector<int>
#define Bt(a) bitset<a>
#define bc __builtin_popcount
#define pc putchar
#define ci const int&
const int mod = 1e9 + 7;
const db eps = 1e-10;
const int inf = (1 << 30);
inline int Max(ci x, ci y) {
	return x > y ? x : y;
}
inline int Min(ci x, ci y) {
	return x < y ? x : y;
}
inline db Max(db x, db y) {
	return x - y > eps ? x : y;
}
inline db Min(db x, db y) {
	return x - y < eps ? x : y;
}
inline int Add(ci x, ci y, ci M = mod) {
	return (x + y) % M;
}
inline int Mul(ci x, ci y, ci M = mod) {
	return 1ll * x * y % M;
}
inline int Dec(ci x, ci y, ci M = mod) {
	return (x - y + M) % M;
}
typedef pair<int, int> pii;
inline int Abs(int x) {
	return x < 0 ? -x : x;
}
//char buf[1<<21],*p1=buf,*p2=buf;
//#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char Obuf[105000],*O=Obuf;//Siz shoule be the size of Out File
int pst[30],ptop;
inline void Fprint() {
	fwrite(Obuf,1,O-Obuf,stdout);
}
inline void Fwrite(int x) {
	if(x==0) {
		*O++='0';
		return;
	}
	if(x<0)*O++='-',x=-x;
	ptop=0;
	while(x)pst[++ptop]=x%10,x/=10;
	while(ptop)*O++=pst[ptop--]+'0';
	if(O-Obuf>100000)Fprint(),O=Obuf;
}
inline int read() {
	int s = 0, w = 1;
	char ch = getchar();
	while (!isdigit(ch)) {
		if (ch == '-') w = -1;
		ch = getchar();
	}
	while (isdigit(ch)) {
		s = s * 10 + ch - '0';
		ch = getchar();
	}
	return s * w;
}
inline void write(int x) {
	if (x < 0)putchar('-'), x = -x;
	if (x > 9)write(x / 10);
	pc(x % 10 + '0');
}
inline int qpow(int x, int y) {
	int res = 1;
	while (y) {
		if (y & 1)res = Mul(res, x);
		x = Mul(x, x);
		y >>= 1;
	}
	return res;
}
inline void cadd(int &x, int y) {
	x += y;
}
inline void cmul(int &x, int y) {
	x *= y;
}
inline void cmax(int &x, int y) {
	x = Max(x, y);
}
inline void cmin(int &x, int y) {
	x = Min(x, y);
}
const int N = 2e5 + 10;

namespace Refined_heart {
	int n,m,p[N];
	int f[2][1<<11];
	void solve() {
		for(int i=1; i<=15; ++i)p[i]=(1<<(i-1));
		while(~scanf("%d%d",&n,&m)) {
			if(n<m)swap(n,m);
			int now=0;
			memset(f,0,sizeof f);
			f[0][(1<<m)-1]=1;
			for(int i=1; i<=n; ++i) {
				for(int j=1; j<=m; ++j) {
					now^=1;
					memset(f[now],0,sizeof f[now]);
					for(int k=0; k<(1<<m); ++k) {
						if(k&p[j]) {
							f[now][k^p[j]]+=f[now^1][k];
						}
						if(j>1&&!(k&p[j-1])&&(k&p[j])) {
							f[now][k|p[j-1]]+=f[now^1][k];
						}
						if(i>1&&!(k&p[j])) {
							f[now][k|p[j]]+=f[now^1][k];
						}
					}
				}
			}
			write(f[now][(1<<m)-1]);
			pc('\n');
		}
	}

}
signed main() {
	Refined_heart::solve();
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章