zoukankan      html  css  js  c++  java
  • P4111 [HEOI2015]小Z的房间

    (color{#0066ff}{ 题目描述 })

    你突然有了一个大房子,房子里面有一些房间。事实上,你的房子可以看做是一个包含n*m个格子的格状矩形,每个格子是一个房间或者是一个柱子。在一开始的时候,相邻的格子之间都有墙隔着。

    你想要打通一些相邻房间的墙,使得所有房间能够互相到达。在此过程中,你不能把房子给打穿,或者打通柱子(以及柱子旁边的墙)。同时,你不希望在房子中有小偷的时候会很难抓,所以你希望任意两个房间之间都只有一条通路。现在,你希望统计一共有多少种可行的方案。

    (color{#0066ff}{输入格式})

    第一行两个数分别表示n和m。

    接下来n行,每行m个字符,每个字符都会是’.’或者’*’,其中’.’代表房间,’*’代表柱子。

    (color{#0066ff}{输出格式})

    一行一个整数,表示合法的方案数 Mod 10^9

    (color{#0066ff}{输入样例})

    2 2
    ..
    ..
        
    2 2
    *.
    .*
    

    (color{#0066ff}{输出样例})

    4
        
        
    0
    

    (color{#0066ff}{数据范围与提示})

    对于前20%的数据,n,m <= 3

    对于前50%的数据,n,m <=5

    对于前100%的数据,n,m<=9

    有40%的数据保证,min(n,m)<=3

    有30%的数据保证,不存在柱子

    (color{#0066ff}{题解})

    裸的矩阵树定理,注意模数不是质数,用辗转相除高斯消元

    #include<bits/stdc++.h>
    #define LL long long
    LL in() {
    	char ch; LL x = 0, f = 1;
    	while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
    	for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
    	return x * f;
    }
    const int mod = 1e9;
    const int maxn = 520;
    LL mp[maxn][maxn], ans = 1;
    int s[maxn][maxn], id[maxn][maxn];
    int rx[] = {1, -1, 0, 0};
    int ry[] = {0, 0, 1, -1};
    int n, m, len;
    char getch() {
    	char ch = getchar();
    	while(ch != '*' && ch != '.') ch = getchar();
    	return ch;
    }
    void gauss() {
    	for(int i = 1; i < len; i++) {
    		for(int j = i + 1; j < len; j++) {
    			while(mp[i][i]) {
    				LL now = mp[j][i] / mp[i][i];
    				for(int k = i; k < len; k++) mp[j][k] = (mp[j][k] - now * mp[i][k] + mod) % mod;
    				if(!mp[j][i]) break;
    				std::swap(mp[i], mp[j]);
    				ans = -ans;
    			}
    		}
    		ans = (ans * mp[i][i]) % mod;
    	}
    	ans = (ans + mod) % mod;
    }
    int main() {
    	n = in(), m = in();
    	for(int i = 1; i <= n; i++)
    		for(int j = 1; j <= m; j++)
    			s[i][j] = getch() == '.', id[i][j] = s[i][j]? ++len : 0;
    	for(int i = 1; i <= n; i++)
    		for(int j = 1; j <= m; j++) {
    			if(!s[i][j]) continue;
    			for(int k = 0; k < 4; k++) {
    				int xx = i + rx[k];
    				int yy = j + ry[k];
    				if(xx >= 1 && yy >= 1 && xx <= n && yy <= m && s[xx][yy])
    					mp[id[i][j]][id[xx][yy]] = mp[id[xx][yy]][id[i][j]] = 1;
    			}
    		}
    	for(int i = 1; i <= len; i++)
    		for(int j = 1; j <= len; j++)
    			if(i ^ j) mp[i][i] += mp[i][j], mp[i][j] = -mp[i][j];
    	gauss();
    	printf("%lld", ans);
    	return 0;
    }
    
  • 相关阅读:
    第五章 Internet协议
    第四章 地址解析协议
    Learn the shell
    Linux学习前的准备
    第三章 链路层
    第二章 Internet 地址结构
    后台数据导出为Excel
    C#开发客户端、JAVA和tomcat开发服务端
    Java基础
    C++学习笔记--(1)
  • 原文地址:https://www.cnblogs.com/olinr/p/10423065.html
Copyright © 2011-2022 走看看