Loading

[URAL1627] Join

Solution

算法标签🏷️:轮廓线 DP

为了保证连通,考虑维护每个节点所在的连通块编号,每次考虑到 \((x,y)\) 位置时,分讨向上和向左两条边的存在情况,并更新每个点所在的连通块编号即可。注意到,可以强制钦定每个点的连通块编号小于等于当前点的位置,这样不难得到状态数是 \(O(m!)\)。每次更新每个点所在的连通块编号的复杂度是 \(O(m)\) 的,综上总复杂度为 \(O(nm^2(m!))\)

以上为核心思路,下文讲述是细节维护,默认标号从 \(0\) 开始。将每个点连通块编号组成的序列压成一个数采用特殊进制即可,第 \(0\) 个位置的上限是 \(0\),第 \(1\) 个位置的上限是 \(1\),……,第 \(m-1\) 个位置的上限是 \(m-1\)。那么,对于序列 \((a_0,a_1,\dots,a_{m-1})\) 来讲,其对应着的值为

\[\sum_{i=0}^{m-1} a_i \cdot i! \]

这样,解决了状态存储的问题。接下来,考虑 \((i,j)\) 位置的转移(令 \(\text{mask}\) 表示状态):

  1. 条件:\(g_{i-1,j}\ne \texttt{*},g_{i,j - 1}\ne \texttt{*},g_{i,j}\ne \texttt{*}\)\(\text{mask}_j\ne \text{mask}_{j-1}\)(解释:第一个条件由题意可得,第二个条件是保证不会连出环)。
    状态变化:为了满足连通块编号小于等于点的位置的条件,需分讨 \(\text{mask}_j\)\(\text{mask}_{j-1}\) 的大小关系:

    • \(\text{mask}_j>\text{mask}_{j-1}\):则将所有连通块编号为 \(\text{mask}_j\) 的位置,连通块编号均改为 \(\text{mask}_{j-1}\)
    • \(\text{mask}_j<\text{mask}_{j-1}\):则将所有连通块编号为 \(\text{mask}_{j-1}\) 的位置,连通块编号均改为 \(\text{mask}_{j}\)

  2. 条件:\(g_{i-1,j}\ne \texttt{*},g_{i,j}\ne \texttt{*}\)\(\text{mask}_j\) 连通块不只有 \(j\) 这一个位置(解释:第一个条件由题意可得,第二个条件是保证连通性,若只有 \(j\) 这一个位置,那么不连接向上的边会导致 \(\text{mask}_j\) 与其余点不可能连通)。
    状态变化:由于第 \(j\) 个位置的连通块编号发生改变,所以需要将所有连通块编号为 \(j\) 的位置更改连通块编号。

  3. 条件:\(g_{i,j-1}\ne \texttt{*},g_{i,j}\ne \texttt{*}\)
    状态变化:不变,因为 \(j\) 位置的连通块编号未发生改变。

  4. 条件:\(\text{mask}_j\) 连通块不只有 \(j\) 这一个位置(解释:保证连通性,若只有 \(j\) 这一个位置,那么不连接向上的边会导致 \(\text{mask}_j\) 与其余点不可能连通)
    状态变化:由于第 \(j\) 个位置的连通块编号发生改变,所以需要将所有连通块编号为 \(j\) 的位置更改连通块编号。

终止状态:若最后一行存在 \(\texttt{*}\),则 \(\texttt{*}\) 位置的连通块编号是其本身,\(\texttt{.}\) 位置的连通块编号均为第一个 \(\texttt{.}\) 位置。

注意⚠️:若最后一行全为 \(\texttt{*}\),则直接删除最后一行,不能保留。

技巧:状态改变可以使用结构体,这样会方便很多。

Code

#include <bits/stdc++.h>
using namespace std;
using i64 = long long;

struct DS {
	int ds[9], pw[9];
	DS(int v) {
		pw[0] = 1;
		for (int i = 1; i < 9; i ++)
			pw[i] = pw[i - 1] * i;
		for (int i = 0; i < 9; i ++)
			ds[i] = v / pw[i] % (i + 1);
	}
	int& operator[] (int x) { return ds[x]; }
	int HASH() {
		int res = 0;
		for (int i = 0; i < 9; i ++)
			res += ds[i] * pw[i];
		return res;
	}
};
int n, m;
char gr[9][9];
int f[362880], g[362880];

int main() {
	cin.tie(0);
	cout.tie(0);
	ios::sync_with_stdio(0);

	cin >> n >> m;
	for (int i = 0; i < n; i ++)
		for (int j = 0; j < m; j ++)
			cin >> gr[i][j];
	while (1) {
		int ok = 1;
		for (int i = 0; i < m; i ++)
			ok &= gr[n - 1][i] == '*';
		if (!ok) break;
		n --;
	}
	
	const int mod = 1e9;
	int mul = 1, st = 0, ed = 0, ok = -1;
	for (int i = 0; i < m; i ++) {
		if (gr[n - 1][i] == '*') ed += i * mul;
		else {
			if (ok == -1) ok = i;
			ed += ok * mul;
		}
		st += i * mul, mul *= (i + 1);
	}
	g[st] = 1;
	for (int i = 0; i < n; i ++)
		for (int j = 0; j < m; j ++) {
			memset(f, 0, sizeof f);
			for (int k = 0; k < mul; k ++) {
				if (!g[k]) continue;
				DS temp(k), back(k);
				// condition 1
				int cur = -1;
				if (i && gr[i - 1][j] == '.' && temp[j] == j) {
					for (int t = j + 1; t < m; t ++)
						if (temp[t] == temp[j]) {
							if (cur == -1) cur = temp[t] = t;
							else temp[t] = cur;
						}
				} else cur = 0;
				temp[j] = j;
				if (~cur) (f[temp.HASH()] += g[k]) %= mod;
				if (gr[i][j] == '*') continue;
				temp = back;
				// condition 2
				if (i && gr[i - 1][j] == '.') (f[k] += g[k]) %= mod;
				// condition 3
				cur = -1;
				if (i && gr[i - 1][j] == '.' && temp[j] == j) {
					for (int t = j + 1; t < m; t ++)
						if (temp[t] == temp[j]) {
							if (cur == -1) cur = temp[t] = t;
							else temp[t] = cur;
						}
				} else cur = 0;
				if (~cur && j && gr[i][j - 1] == '.') {
					temp[j] = temp[j - 1];
					(f[temp.HASH()] += g[k]) %= mod;
				}
				temp = back;
				// condition 4
				if (temp[j] != temp[j - 1] && i && j && 
					gr[i][j - 1] == '.' && gr[i - 1][j] == '.') {
					int u = temp[j], v = temp[j - 1];
					if (u < v) swap(u, v);
					for (int t = 0; t < m; t ++)
						if (temp[t] == u) temp[t] = v;
					(f[temp.HASH()] += g[k]) %= mod;
				}
			}
			swap(f, g);
		}

	cout << g[ed] << endl;

	return 0;
}

Debug

【输入】

4 4
****
*..*
*..*
****

【输出】

4
posted @ 2025-04-01 21:07  Pigsyy  阅读(32)  评论(0)    收藏  举报