括号表示法写的插头 dp,厌氧。
查看原帖
括号表示法写的插头 dp,厌氧。
726525
CuteChat楼主2024/5/23 16:31
#include <bits/stdc++.h>
using namespace std;
#define int __int128
long long n, m;
int nxt[531441*3][3], val[531441*3], nodet;
int ans = 0;
char s[129][129];

struct Info {
	char s[16];
	int hashv() {
		int now = 0;
		for (int i = 1; i <= m; ++i) {
			if (!nxt[now][s[i]]) {
				nxt[now][s[i]] = ++nodet;
			}
			now = nxt[now][s[i]];
		}
		if (!val[now]) val[now] = ++ans;
		return val[now];
	}
	char & operator [](const int a) {
		return s[a];
	}
};

__int128 dp[22][12][18898];

// 0 表无插头,1 表左括号,2 表右括号

__int128 dfs(int i, int j, Info f) {
//	printf("%d %d\n", i, j);
//	for (int k = 1; k <= m + 1; ++k) printf("%d%c", f[k], " \n"[k == m + 1]);
	if (i == n + 1) {
		for (int k = 1; k <= m + 1; ++k) {
			if (f[k]) return 0;
		}
		return 1;
	}
	if (j == m + 1) {
		if (f[j]) return 0;
		Info newf = {};
		for (int k = 1; k <= m; ++k) {
			newf[k + 1] = f[k];
		}
		return dfs(i + 1, 1, newf);
	}
	if (s[i][j] == '*') {
		if (f[j] || f[j + 1]) return 0;
		return dfs(i, j + 1, f);
	}
	int hs = f.hashv();
	if (dp[i][j][hs] != -1) return dp[i][j][hs];
	if (f.s[j] == 0 && f.s[j + 1] == 0) {
		f.s[j] = 1;
		f.s[j + 1] = 2;
		return dp[i][j][hs] = dfs(i, j + 1, f);
	} else if (f[j] == 0 && f[j + 1] == 2) {
		__int128 ans = dfs(i, j + 1, f);
		f[j] = 2;
		f[j + 1] = 0;
		return dp[i][j][hs] = ans + dfs(i, j + 1, f);
	} else if (f[j] == 0 && f[j + 1] == 1) {
		__int128 ans = dfs(i, j + 1, f);
		f[j] = 1;
		f[j + 1] = 0;
		return dp[i][j][hs] = ans+ dfs(i, j + 1, f);
	} else if (f[j] == 2 && f[j + 1] == 2) {
		int st[14] = {}, top = 0, tmp[3] = {}, tot = 0;
		for (int k = 1; k <= m + 1; ++k) {
			if (f[k] == 1) st[++top] = k;
			else if (f[k] == 2) {
				if (k == j) tmp[++tot] = st[top];
				if (k == j + 1) tmp[++tot] = st[top];
				--top;
			}
		}
		f[min(tmp[1], tmp[2])] = 1;
		f[max(tmp[1], tmp[2])] = 2;
		f[j] = f[j + 1] = 0;
		return dp[i][j][hs] = dfs(i, j + 1, f);
	} else if (f[j] == 2 && f[j + 1] == 1) {
		f[j] = 0;
		f[j + 1] = 0;
		return dp[i][j][hs] = dfs(i, j + 1, f);
	} else if (f[j] == 2 && f[j + 1] == 0) {
		__int128 ans = dfs(i, j + 1, f);
		f[j] = 0, f[j + 1] = 2;
		return dp[i][j][hs] = ans+ dfs(i, j + 1, f);
	} else if (f[j] == 1 && f[j + 1] == 2) {
		if (i == n && j == m) {
			for (int k = 1; k <= m - 1; ++k) if (f[k]) return dp[i][j][hs] = 0;
			return dp[i][j][hs] = 1;
		} else return dp[i][j][hs] = 0;
	} else if (f[j] == 1 && f[j + 1] == 1) {
		int st[14] = {}, top = 0, tmp[5], tot = 0;
		for (int k = 1; k <= m + 1; ++k) {
			if (f[k] == 1) st[++top] = k;
			else if (f[k] == 2) {
				if (st[top] == j) tmp[++tot] = k;
				if (st[top] == j + 1) tmp[++tot] = k;
				--top;
			}
		}
		f[min(tmp[1], tmp[2])] = 1;
		f[max(tmp[1], tmp[2])] = 2;
		f[j] = f[j + 1] = 0;
		return dp[i][j][hs] = dfs(i, j + 1, f);
	} else if (f[j] == 1 && f[j + 1] == 0) {
		__int128 ans = dfs(i, j + 1, f);
		f[j] = 0, f[j + 1] = 1;
		return dp[i][j][hs] = ans + dfs(i, j + 1, f);
	} else return 0;
}

void write(__int128 i, bool fir = 0) {
	if (i == 0) {
	    if (!fir) putchar('0');
	    return;
	}
	write(i / 10, 1); putchar(i % 10 + '0');
}

signed main() {
	scanf("%lld%lld", &m, &n);
	if (n == 1 || m == 1)return puts("1"), 0;
	memset(dp, 255, sizeof(dp));
	write(dfs(1, 1, {}) * 2);
	return 0;
}

直接套的板子,所以会出现 s[i][j] 这个神奇的东西。

然后 f[i]=0 表示对应轮廓线上无插头,f[i]=1 表示对应轮廓线上有一个插头,且代表的是左括号,f[i]=2 同理。

哈希用的是字典树哈希。

用记忆化搜索写的。

2024/5/23 16:31
加载中...