题目描述

给定一个 $n\times m$ 的方格图,每个格子有 ↑、↓、←、→,表示从该格子能够走到相邻的哪个格子。
有一些格子是空着的,需要填上四者之一,需要满足:最终的方格图中,从任意一个位置出发都能够走出方格图。求方案数 mod 10^9+7。

$数据组数\le 10$ ,$n,m\le 300$ ,$空格子数k\le 200$


题解

并查集+矩阵树定理

由于k很小,又是计数问题,考虑矩阵树定理。

先使用并查集处理出从每个位置开始,最终会走到哪个位置。显然如果有环则答案为0,否则一定走到的是一个空格子或方格图外部。

这样就不用考虑已填好的格子的走法,只需要考虑空格子的走法即可。

每个空格子需要走到方格图外部,不能有环,相当于是一棵以方格图外部为根的内向树形图。

考虑每个空格子4个方向会走到哪个空格子(或外部),连边,矩阵树定理求解即可。

本题要求的是内向树,因此求 出度矩阵-邻接矩阵 删去根节点所在行列,得到的行列式的值 即可。

时间复杂度 $O(nm+k^3)$

#include <cstdio>
#include <cstring>
#include <algorithm>
#define mod 1000000007
using namespace std;
typedef long long ll;
int id[210][210] , f[40010] , flag , v[40010] , wx[310] , wy[310];
ll a[310][310];
char str[210];
inline ll pow(ll x , int y)
{
ll ans = 1;
while(y)
{
if(y & 1) ans = ans * x % mod;
x = x * x % mod , y >>= 1;
}
return ans;
}
int find(int x)
{
return x == f[x] ? x : f[x] = find(f[x]);
}
inline void link(int x , int y)
{
x = find(x) , y = find(y);
if(x == y) flag = 1;
f[x] = y;
}
int main()
{
int T;
scanf("%d" , &T);
while(T -- )
{
int n , m , p = 0 , i , j , k , d = 0;
ll t , ans = 1;
scanf("%d%d" , &n , &m);
memset(id , 0 , sizeof(id)) , flag = 0;
for(i = 1 ; i <= n ; i ++ )
for(j = 1 ; j <= m ; j ++ )
id[i][j] = (i - 1) * m + j;
for(i = 0 ; i <= n * m ; i ++ ) f[i] = i;
for(i = 1 ; i <= n ; i ++ )
{
scanf("%s" , str + 1);
for(j = 1 ; j <= m ; j ++ )
{
switch(str[j])
{
case 'L': link(id[i][j] , id[i][j - 1]); break;
case 'R': link(id[i][j] , id[i][j + 1]); break;
case 'U': link(id[i][j] , id[i - 1][j]); break;
case 'D': link(id[i][j] , id[i + 1][j]); break;
default: v[id[i][j]] = ++p , wx[p] = i , wy[p] = j;
}
}
}
if(flag) puts("0");
else
{
memset(a , 0 , sizeof(a));
for(i = 1 ; i <= p ; i ++ )
{
a[i][i] += 4;
a[i][v[find(id[wx[i]][wy[i] - 1])]] -- ;
a[i][v[find(id[wx[i]][wy[i] + 1])]] -- ;
a[i][v[find(id[wx[i] - 1][wy[i]])]] -- ;
a[i][v[find(id[wx[i] + 1][wy[i]])]] -- ;
}
for(i = 1 ; i <= p ; i ++ )
for(j = 1 ; j <= p ; j ++ )
a[i][j] = (a[i][j] + mod) % mod;
for(i = 1 ; i <= p ; i ++ )
{
for(j = i ; j <= p ; j ++ )
if(a[i][j])
break;
if(j > p) continue;
if(j != i)
{
d ^= 1;
for(k = i ; k <= p ; k ++ )
swap(a[i][k] , a[j][k]);
}
ans = ans * a[i][i] % mod;
t = pow(a[i][i] , mod - 2);
for(j = i ; j <= p ; j ++ ) a[i][j] = a[i][j] * t % mod;
for(j = i + 1 ; j <= p ; j ++ )
for(t = a[j][i] , k = i ; k <= p ; k ++ )
a[j][k] = (a[j][k] - a[i][k] * t % mod + mod) % mod;
}
for(i = 1 ; i <= p ; i ++ ) ans = ans * a[i][i] % mod;
if(d) ans = (mod - ans) % mod;
printf("%lld\n" , ans);
}
}
return 0;
}

【bzoj5133】[CodePlus2017年12月]白金元首与独舞 并查集+矩阵树定理的更多相关文章

  1. [BZOJ5133][CodePlus2017年12月]白金元首与独舞

    bzoj luogu 题意 给你一个\(n*m\)的网格,每个位置上有一个箭头指向上或下或左或右.有些位置上还没有箭头,现在要求你在这些没有箭头的位置上填入箭头,使得从网格的任意一个位置开始,都可以沿 ...

  2. 【BZOJ5133】[CodePlus2017年12月]白金元首与独舞 矩阵树定理

    [BZOJ5133][CodePlus2017年12月]白金元首与独舞 题面:www.lydsy.com/JudgeOnline/upload/201712/div1.pdf 题解:由于k很小,考虑用 ...

  3. [LOJ#6259]「CodePlus 2017 12 月赛」白金元首与独舞

    [LOJ#6259]「CodePlus 2017 12 月赛」白金元首与独舞 试题描述 到河北省 见斯大林 / 在月光下 你的背影 / 让我们一起跳舞吧 うそだよ~ 河北省怎么可能有 Stalin. ...

  4. BZOJ5131: [CodePlus2017年12月]可做题2

    BZOJ没有题面,差评 洛谷的题目链接 题解 其实这题很久之前就写了,也想写个题解但是太懒了,咕到了今天 在typora写完题解不想copy过来再改格式了,于是直接贴截图qwq #include &l ...

  5. 【LibreOJ】#6259. 「CodePlus 2017 12 月赛」白金元首与独舞

    [题目]给定n行m列的矩阵,每个位置有一个指示方向(上下左右)或没有指示方向(任意选择),要求给未定格(没有指示方向的位置)确定方向,使得从任意一个开始走都可以都出矩阵,求方案数.n,m<=20 ...

  6. 「CodePlus 2017 12 月赛」白金元首与独舞

    description 题面 data range \[ 1 \leq T \leq 10, 1 \leq n, m \leq 200 , 0 \leq k \leq \min(nm, 300)\] ...

  7. 走进矩阵树定理--「CodePlus 2017 12 月赛」白金元首与独舞

    n,m<=200,n*m的方阵,有ULRD表示在这个格子时下一步要走到哪里,有一些待决策的格子用.表示,可以填ULRD任意一个,问有多少种填法使得从每个格子出发都能走出这个方阵,答案取模.保证未 ...

  8. loj6259「CodePlus 2017 12 月赛」白金元首与独舞

    分析 我们将没连的点连向周围四个点 其余的按照给定的方向连 我们将所有连出去的位置统一连到0点上 再以0作为树根 于是就将问题转化为了有向图内向树计数 代码 #include<iostream& ...

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

    \(\mathcal{Description}\)   link.   给定一个 \(n\times m\) 的网格图,一些格子指定了走出该格的方向(上下左右),而有 \(k\) 格可以任意指定走出方 ...

随机推荐

  1. OO原则汇总

    SOLID原则:http://www.cnblogs.com/lanxuezaipiao/archive/2013/06/09/3128665.html https://www.cnblogs.com ...

  2. oracle基础命令

    oracle使用步骤: 一.oracle安装 两个文件解压到同一文件夹,doc为说明/使用文档 二.oracle启动: 1.启动oracle:启动监听和自定义库 2.启动cmd->sqlplus ...

  3. 【转载】TCP/IP 之 大明王朝邮差

    原文:TCP/IP 之 大明王朝邮差 原创 2016-05-12 刘欣 码农翻身 前言: 本文主要想说一下TCP的知识, 比喻有不恰当之处,敬请包涵. 大明王朝天启四年, 清晨. 天色刚蒙蒙亮,我就赶 ...

  4. ES6 localStorage 类库

    无意中看到的,记录下. 用到了es6语法.支持在js中写构造函数 class CovLocalDB { constructor (name) { this.LS = null this.name = ...

  5. (转) 转换Drupal7模块到Drupal8

    转载地址:http://verynull.com/2015/11/02/Converting-7-x-modules-to-8-x/ 本节主要介绍如何把drupal7的模块转化为drupal8.参考资 ...

  6. 「日常训练」Magic Stones(CodeForces-1110E)

    题意 给定两个数组c和t,可以对c数组中的任何元素变换\(c_i\)​成\(c_{i+1}+c_{i-1}-c_i\)​,问c数组在若干次变换后能否变换成t数组. 分析 这种魔法题目我是同样的没做过. ...

  7. Jmeter接口测试(一) Jmeter简介

    一.Jmeter介绍 (一)Jmeter简介 Apache JMeter 是 Apache 组织的开放源代码项目,是一个纯 Java 桌面应用,用于压力测试和性能测试.它最初被设计用于 Web 应用测 ...

  8. Codeforces Round #553 (Div. 2) C

    C. Problem for Nazar time limit per test 1 second memory limit per test 256 megabytes input standard ...

  9. Python3【基础】-表达式与运算符

    一.什么是表达式? 1+2*3就是一个表达式,这里的加号和乘号叫做运算符,1.2.3叫做操作数.1+2*3计算的结果是7,计算结果可以存到一个变量中,即:res = 1 + 2 * 3. 所谓的表达式 ...

  10. ES6的新特性(16)——Generator 函数的语法

    Generator 函数的语法 简介 基本概念 Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同.本章详细介绍 Generator 函数的语法和 API,它的 ...