[Luogu P3290] [BZOJ 4572] [SCOI2016]圍棋

洛谷傳送門

BZOJ傳送門

題目描述

近日,谷歌研發的圍棋AI—AlphaGo以4:1的比分戰勝了曾經的世界冠軍李世石,這是人工智能領域的又一里程碑。

與傳統的搜索式AI不同,AlphaGo使用了最近十分流行的卷積神經網絡模型。在卷積神經網絡模型中,棋盤上每一塊特定大小的區域都被當做一個窗口。例如棋盤的大小爲565*6,窗口大小爲242*4,那麼棋盤中共有1212個窗口。此外,模型中預先設定了一些模板,模板的大小與窗口的大小是一樣的。

下圖展現了一個565*6的棋盤和兩個242*4的模板。

對於一個模板,只要棋盤中有某個窗口與其完全匹配,我們稱這個模板是被激活的,否則稱這個模板沒有被激活。

例如圖中第一個模板就是被激活的,而第二個模板就是沒有被激活的。我們要研究的問題是:對於給定的模板,有多少個棋盤可以激活它。爲

了簡化問題,我們拋開所有圍棋的基本規則,只考慮一個nmn*m的棋盤,每個位置只能是黑子、白子或無子三種情況,換句話說,這樣的棋盤共有3nm3^{n*m}種。此外,我們會給出qq2c2*c的模板。

我們希望知道,對於每個模板,有多少種棋盤可以激活它。強調:模板一定是兩行的。

輸入輸出格式

輸入格式:

輸入數據的第一行包含四個正整數nnmmccqq,分別表示棋盤的行數、列數、模板的列數和模板的數量。

隨後2×q2×q行,每連續兩行描述一個模板。其中,每行包含cc個字符,字符一定是’W’,'B’或’X’中的一個,表示白子、黑子或無子三種情況的一種。N100,M12,C6,Q5N\le 100,M\le 12,C\le 6,Q\le 5

輸出格式:

輸出應包含qq行,每行一個整數,表示符合要求的棋盤數量。由於答案可能很大,你只需要輸出答案對1,000,000,0071,000,000,007取模後的結果即可。

輸入輸出樣例

輸入樣例#1:

3 1 1 2
B
W
B
B

輸出樣例#1:

6
5

解題分析

好難的DP啊QAQ

判重很麻煩, 轉化爲3nm3^{nm}-完全不存在的方案數。

顯然有個大暴力DPDP: 直接壓每行選擇的方式,然鵝這樣是n32mn3^{2m}, 完全過不了。

那麼怎麼優化狀態?發現對於當前行我們不關心上一行具體填的是什麼,只關心具體哪些位置可以匹配第一行的模板串,然後dp時記錄匹配到哪個位置, 這樣就可以做到大概n22mn2^{2m}, 仍然很涼。

繼續觀察不難得出, 假設現在考慮第ii行第jj列的位置, 那麼i1i-1j1j-1列及之前的信息對我們完全沒有用。

所有可以維護一個輪廓線, 表示這些位置能否作爲一個匹配第一行模式串的結尾位置。 然後可能可以匹配的位置實際上每列只有mc+1m-c+1個, 所以輪廓線長度也就是mc+1m-c+1

然後轉移可以通過預處理kmp, 枚舉字符做到。

代碼如下:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#define R register
#define IN inline
#define MOD 1000000007
#define W while
#define gc getchar()
#define ll long long
int n, m, c, q, all;
const int SIZ = 1 << 12;
int nex1[10], nex2[10], to1[10][3], to2[10][3];
int dat1[10], dat2[10], dp[2][SIZ][7][7];
char str1[10], str2[10];
IN int give(R char c)
{
	if (c == 'W') return 0;
	if (c == 'B') return 1;
	return 2;
}
IN int fpow(R int base, R int tim)
{
	int ret = 1;
	W (tim)
	{
		if (tim & 1) ret = 1ll * ret * base % MOD;
		base = 1ll * base * base % MOD, tim >>= 1;
	}
	return ret;
}
IN void add(int &tar, R int ad) {tar += ad; if (tar >= MOD) tar -= MOD;}
int main(void)
{
	scanf("%d%d%d%d", &n, &m, &c, &q);
	all = 1 << m - c + 1;
	R int s, a, b, col, i, j, now, cur, pre, p1, p2, nex;
	W (q--)
	{
		pre = 0, cur = 1;
		scanf("%s%s", str1 + 1, str2 + 1);
		for (i = 1; i <= c; ++i)
		dat1[i] = give(str1[i]), dat2[i] = give(str2[i]);
		for (i = 2, now = 0; i <= c; ++i)
		{
			W (now && dat1[now + 1] != dat1[i]) now = nex1[now];
			if (dat1[now + 1] == dat1[i]) ++now;
			nex1[i] = now;
		}
		for (i = 2, now = 0; i <= c; ++i)
		{
			W (now && dat2[now + 1] != dat2[i]) now = nex2[now];
			if (dat2[now + 1] == dat2[i]) ++now;
			nex2[i] = now;
		}
		for (i = 0; i < c; ++i)
		for (col = 0, now = i; col < 3; ++col, now = i)
		{
			W (now && dat1[now + 1] != col) now = nex1[now];
			if (dat1[now + 1] == col) ++now;
			to1[i][col] = now;
		}
		for (i = 0; i < c; ++i)
		for (col = 0, now = i; col < 3; ++col, now = i)
		{
			W (now && dat2[now + 1] != col) now = nex2[now];
			if (dat2[now + 1] == col) ++now;
			to2[i][col] = now;
		}
		std::memset(dp, 0, sizeof(dp));
		dp[pre][0][0][0] = 1;
		for (i = 1; i <= n; ++i)
		{
			std::memset(dp[cur], 0, sizeof(dp[cur]));
			for (s = 0; s < all; ++s)
			for (a = 0; a < c; ++a)
			for (b = 0; b < c; ++b)
			if (dp[pre][s][a][b])
			add(dp[cur][s][0][0], dp[pre][s][a][b]);
			std::swap(pre, cur);
			for (j = 1; j <= m; ++j)
			{
				std::memset(dp[cur], 0, sizeof(dp[cur]));
				for (s = 0; s < all; ++s)
				for (a = 0; a < c; ++a)
				for (b = 0; b < c; ++b)
				if (dp[pre][s][a][b])
				{
					for (R int col = 0; col < 3; ++col)
					{
						nex = s;
						p1 = to1[a][col];
						p2 = to2[b][col];
						if (j >= c && ((s >> j - c) & 1)) nex ^= 1 << j - c;
						if (p1 == c) nex ^= 1 << j - c, p1 = nex1[c];
						if (p2 == c)
						{
							if ((s >> j - c) & 1) continue;
							p2 = nex2[c];
						}
						add(dp[cur][nex][p1][p2], dp[pre][s][a][b]);
					}
				}
				std::swap(cur, pre);
			}
		}
		int ans = fpow(3, n * m);
		for (s = 0; s < all; ++s)
		for (a = 0; a < c; ++a)
		for (b = 0; b < c; ++b)
		add(ans, MOD - dp[pre][s][a][b]);
		printf("%d\n", ans);
	}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章