ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Solution -「Code+#2」「洛谷 P4033」白金元首与独舞

2020-07-02 13:06:56  阅读:176  来源: 互联网

标签:+# P4033 洛谷 int gar ret MAXN return const


\(\mathcal{Description}\)

  link.
  给定一个 \(n\times m\) 的网格图,一些格子指定了走出该格的方向(上下左右),而有 \(k\) 格可以任意指定走出方向。求指定的方案数,使得从任意格子都可以走出网格图。
  \(n,m\le200;k\le300\)。

\(\mathcal{Solution}\)

  令“走出边界”为走到一个特殊点,建图,其中未指定方向的点向四周连边,相当于求以特殊点为根的内向树个数,跑矩阵树定理即可。复杂度 \(\mathcal O(n^3m^3)\)。
  考虑优化,生成树个数实质上只与不定向的点有关,所以直接预处理出每个不定向点向上/下/左/右走到的第一个不定向点,向其连边,再跑矩阵树。复杂度 \(\mathcal O(k^3)\)。

\(\mathcal{Code}\)

#include <cstdio>
#include <cstring>
#include <iostream>

const int MOD = 1e9 + 7, MAXN = 200, MAXP = 300;
int T, N, M, K[MAXP + 5][MAXP + 5], col[MAXN + 5][MAXN + 5], unk[MAXN + 5][MAXN + 5], cnt;
char gar[MAXN + 5][MAXN + 5];

inline int qkpow ( int a, int b, const int p = MOD ) {
	int ret = 1;
	for ( ; b; a = 1ll * a * a % p, b >>= 1 ) ret = 1ll * ret * ( b & 1 ? a : 1 ) % p;
	return ret;
}

inline int det ( const int n ) {
	int ret = 1, swp = 1;
	for ( int i = 2; i <= n; ++ i ) {
		for ( int j = i; j <= n; ++ j ) {
			if ( K[j][i] ) {
				if ( i ^ j ) std::swap ( K[i], K[j] ), swp *= -1;
				break;
			}
		}
		if ( ! ( ret = 1ll * ret * K[i][i] % MOD ) ) return 0;
		for ( int j = i + 1, inv = qkpow ( K[i][i], MOD - 2 ); j <= n; ++ j ) {
			int d = 1ll * K[j][i] * inv % MOD;
			for ( int k = i; k <= n; ++ k ) K[j][k] = ( K[j][k] - 1ll * K[i][k] * d % MOD + MOD ) % MOD;
		}
	}
	return ( ret * swp + MOD ) % MOD;
}

inline bool findLoop ( const int x, const int y, const int cur ) {
	if ( x < 1 || x > N || y < 1 || y > M || gar[x][y] == '.' ) return false;
	if ( col[x][y] == cur ) return true;
	if ( col[x][y] ) return false;
	col[x][y] = cur;
	if ( gar[x][y] == 'L' ) return findLoop ( x, y - 1, cur );
	if ( gar[x][y] == 'R' ) return findLoop ( x, y + 1, cur );
	if ( gar[x][y] == 'U' ) return findLoop ( x - 1, y, cur );
	if ( gar[x][y] == 'D' ) return findLoop ( x + 1, y, cur );
	return false;
}

inline int findUnknown ( const int x, const int y ) {
	if ( x < 1 || x > N || y < 1 || y > M ) return 1;
	if ( unk[x][y] ) return unk[x][y];
	int& ret = unk[x][y];
	if ( gar[x][y] == 'L' ) ret = findUnknown ( x, y - 1 );
	if ( gar[x][y] == 'R' ) ret = findUnknown ( x, y + 1 );
	if ( gar[x][y] == 'U' ) ret = findUnknown ( x - 1, y );
	if ( gar[x][y] == 'D' ) ret = findUnknown ( x + 1, y );
	return ret;
}

inline void add ( const int s, int t ) {
	if ( ! t ) t = 1;
	++ K[s][s], -- K[s][t];
	if ( K[s][t] < 0 ) K[s][t] += MOD;
}

int main () {
	for ( scanf ( "%d", &T ); T --; ) {
		memset ( K, 0, sizeof K );
		memset ( col, 0, sizeof col );
		memset ( unk, 0, sizeof unk );
		scanf ( "%d %d", &N, &M ), cnt = 1;
		for ( int i = 1; i <= N; ++ i ) {
			scanf ( "%s", gar[i] + 1 );
			for ( int j = 1; j <= M; ++ j ) {
				if ( gar[i][j] == '.' ) {
					unk[i][j] = ++ cnt;
				}
			}
		}
		bool loop = false;
		for ( int i = 1, cur = 1; i <= N && ! loop; ++ i ) {
			for ( int j = 1; j <= M && ! loop; ++ j ) {
				loop |= findLoop ( i, j, cur ++ );
			}
		}
		if ( loop ) { puts ( "0" ); continue; }
		for ( int i = 1; i <= N; ++ i ) {
			for ( int j = 1; j <= M; ++ j ) {
				findUnknown ( i, j );
			}
		}
		for ( int i = 1; i <= N; ++ i ) {
			for ( int j = 1; j <= M; ++ j ) {
				if ( gar[i][j] == '.' ) {
					add ( unk[i][j], unk[i][j - 1] );
					add ( unk[i][j], unk[i][j + 1] );
					add ( unk[i][j], unk[i - 1][j] );
					add ( unk[i][j], unk[i + 1][j] );
				}
			}
		}
		printf ( "%d\n", det ( cnt ) );
	}
	return 0;
}

标签:+#,P4033,洛谷,int,gar,ret,MAXN,return,const
来源: https://www.cnblogs.com/rainybunny/p/13224064.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有