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

试题描述

到河北省 见斯大林 / 在月光下 你的背影 / 让我们一起跳舞吧

うそだよ~ 河北省怎么可能有 Stalin。

可是…… 可是如果 Stalin 把自己当作炸弹扔到地堡花园里来了呢?

怀揣着这份小小的希望,元首 Adolf 独自走进了花园。终有一天会重逢的吧,Stalin。或许是在此处,或许是在遥远的彼方。


无论如何,在此之前,好好装点一番花园,编排一段优美的舞步吧!

元首把花园分为 \(n\) 行 \(m\) 列的网格。每个格子中都可以放置一个标识,指向上、下、左、右四个方向中的任意一个。元首位于一个格子时,会按照其中标识所指的方向进入周围的格子,或者走出花园(即目的格子不在网格之内)。举个例子 —— 对于下面的放置方式,元首从第 \(3\) 行第 \(2\) 列的格子开始,会沿着以红色标出的路径走出花园;从第 \(2\) 行第 \(2\) 列的格子开始,则会在以蓝色标出的环路内不断地行走。

元首已经设计好了大部分格子的标识。元首用字符 LRUD 分别表示指向左、右、上、下四个方向的标识,用字符 . 表示未决定的格子。现在,元首希望将每个 . 替换为 LRUD 中任意一种,使得从花园中的任意一个格子出发,按照上述规则行走,都可以最终走出花园。

你需要编写程序帮助元首计算替换的不同方案数。两个方案不同当且仅当存在一个格子,使得两个方案中该格子内的标识不同。当然,由于答案可能很大,只需给出方案数除以 \(10^9 + 7\) 所得的余数即可。

输入

从标准输入读入数据。

输入的第一行包含一个正整数 \(T\) —— 测试数据的组数。接下来包含 \(T\) 组测试数据,格式如下,测试数据间没有空行。

  • 第 \(1\) 行:两个空格分隔的正整数 \(n\)、\(m\) —— 依次表示花园被分成的行数和列数。

  • 接下来 \(n\) 行:每行一个长度为 \(m\) 的由字符 LRUD. 组成的字符串 —— 表示花园内已经确定的格子状态。

输出

输出到标准输出。

对于每组测试数据输出一行 —— 满足条件的方案数除以 \(10^9 + 7\) 所得的余数。

输入示例

5
3 9
LLRRUDUUU
LLR.UDUUU
LLRRUDUUU
4 4
LLRR
L.LL
RR.R
LLRR
4 3
LRD
LUL
DLU
RDL
1 2
LR
2 2
..
..

输出示例

3
8
0
1
192

数据规模及约定

令 \(k\) 表示标记未确定(即包含 “.”)的格子总数。

对于所有数据,有 \(1 \leq T \leq 10\),\(1 \leq n, m \leq 200\),\(0 \leq k \leq \min(nm, 300)\)。

题解

矩阵树定理,有向图有根树的情况。

去掉所有自环,主对角线上第 \(i\) 行第 \(i\) 列是 \(i\) 这个点的出度,剩下的是邻接矩阵取相反数。然后求的是删掉根节点所在行列的余子式的行列式。

注意这个求的是指向根的树形图

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
#define rep(i, s, t) for(int i = (s); i <= (t); i++)
#define dwn(i, s, t) for(int i = (s); i >= (t); i--) int read() {
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
return x * f;
} #define maxr 210
#define maxnode 40010
#define maxn 310
#define MOD 1000000007
#define LL long long int r, c;
char Map[maxr][maxr]; struct Graph {
int n, m, head[maxnode], nxt[maxnode], to[maxnode];
Graph() {}
void clear() {
m = 0; memset(head, 0, sizeof(head));
return ;
}
void AddEdge(int a, int b) {
to[++m] = b; nxt[m] = head[a]; head[a] = m;
return ;
}
} G; int id(int i, int j) { return (i - 1) * c + j; }
int vis[maxnode];
bool dfs(int u) {
if(vis[u] == 2) return 0;
if(vis[u]) return 1;
vis[u] = 2;
for(int e = G.head[u]; e; e = G.nxt[e]) if(!dfs(G.to[e])) return 0;
vis[u] = 1;
return 1;
} int fa[maxnode];
int findset(int x) { return x == fa[x] ? x : fa[x] = findset(fa[x]); } int n, trid[maxnode];
int ID(int u) { return trid[u] ? trid[u] : trid[u] = ++n; } int A[maxn][maxn], tA[maxn][maxn];
void MatAddEdge(int a, int b) {
if(a == b) return ;
tA[a][a]++; tA[a][b]--;
return ;
}
void elim(int *a, int *b, int tar) {
if(!b[tar]) return ;
int rate = a[tar] / b[tar];
rep(i, 1, n) a[i] = ((LL)a[i] - (LL)b[i] * rate % MOD + MOD) % MOD;
elim(b, a, tar);
return ;
}
int solve() {
n--;
int sgn = 1;
rep(i, 1, n) rep(j, 1, n) if(A[i][j] < 0) A[i][j] += MOD;
rep(i, 1, n)
rep(j, i + 1, n) if(A[j][i]) {
elim(A[i], A[j], i);
if(!A[i][i]) swap(A[i], A[j]), sgn = -sgn;
}
int sum = 1;
rep(i, 1, n) sum = (LL)sum * A[i][i] % MOD;
return (sum * sgn + MOD) % MOD;
} int main() {
int T = read();
while(T--) {
r = read(); c = read(); G.n = r * c + 1; G.clear();
rep(i, 1, G.n) fa[i] = i;
rep(i, 1, r) scanf("%s", Map[i] + 1);
rep(i, 1, r) rep(j, 1, c) if(isalpha(Map[i][j])) {
if(Map[i][j] == 'D') {
G.AddEdge(id(i, j), i < r ? id(i + 1, j) : G.n);
int u = findset(id(i, j)), v = findset(i < r ? id(i + 1, j) : G.n);
if(u != v) fa[v] = u;
}
if(Map[i][j] == 'U') {
G.AddEdge(id(i, j), i > 1 ? id(i - 1, j) : G.n);
int u = findset(id(i, j)), v = findset(i > 1 ? id(i - 1, j) : G.n);
if(u != v) fa[v] = u;
}
if(Map[i][j] == 'R') {
G.AddEdge(id(i, j), j < c ? id(i, j + 1) : G.n);
int u = findset(id(i, j)), v = findset(j < c ? id(i, j + 1) : G.n);
if(u != v) fa[v] = u;
}
if(Map[i][j] == 'L') {
G.AddEdge(id(i, j), j > 1 ? id(i, j - 1) : G.n);
int u = findset(id(i, j)), v = findset(j > 1 ? id(i, j - 1) : G.n);
if(u != v) fa[v] = u;
}
}
memset(vis, 0, sizeof(vis));
bool ok = 1;
rep(i, 1, G.n) if(!vis[i] && !dfs(i)){ puts("0"); ok = 0; break; }
if(!ok) continue; memset(trid, 0, sizeof(trid)); n = 0;
memset(tA, 0, sizeof(tA));
rep(i, 1, r) rep(j, 1, c) if(Map[i][j] == '.') {
int u = findset(id(i, j));
MatAddEdge(ID(u), ID(findset(i < r ? id(i + 1, j) : G.n)));
MatAddEdge(ID(u), ID(findset(i > 1 ? id(i - 1, j) : G.n)));
MatAddEdge(ID(u), ID(findset(j < c ? id(i, j + 1) : G.n)));
MatAddEdge(ID(u), ID(findset(j > 1 ? id(i, j - 1) : G.n)));
} int ci = 0, cj = 0;
rep(i, 1, n) if(i != ID(findset(G.n))) {
ci++;
cj = 0;
rep(j, 1, n) if(j != ID(findset(G.n))) A[ci][++cj] = tA[i][j];
}
printf("%d\n", solve());
} return 0;
}

[LOJ#6259]「CodePlus 2017 12 月赛」白金元首与独舞的更多相关文章

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

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

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

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

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

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

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

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

  5. loj #6250. 「CodePlus 2017 11 月赛」找爸爸

    #6250. 「CodePlus 2017 11 月赛」找爸爸 题目描述 小 A 最近一直在找自己的爸爸,用什么办法呢,就是 DNA 比对. 小 A 有一套自己的 DNA 序列比较方法,其最终目标是最 ...

  6. [LOJ 6249]「CodePlus 2017 11 月赛」汀博尔

    Description 有 n 棵树,初始时每棵树的高度为 H_i,第 i 棵树每月都会长高 A_i.现在有个木料长度总量为 S 的订单,客户要求每块木料的长度不能小于 L,而且木料必须是整棵树(即不 ...

  7. [LOJ 6248]「CodePlus 2017 11 月赛」晨跑

    Description “无体育,不清华”.“每天锻炼一小时,健康工作五十年,幸福生活一辈子” 在清华,体育运动绝对是同学们生活中不可或缺的一部分.为了响应学校的号召,模范好学生王队长决定坚持晨跑.不 ...

  8. 「CodePlus 2017 12 月赛」火锅盛宴(模拟+树状数组)

    1A,拿来练手的好题 用一个优先队列按煮熟时间从小到大排序,被煮熟了就弹出来. 用n个vector维护每种食物的煮熟时间,显然是有序的. 用树状数组维护每种煮熟食物的数量. 每次操作前把优先队列里煮熟 ...

  9. 「CodePlus 2017 12 月赛」可做题2(矩阵快速幂+exgcd+二分)

    昨天这题死活调不出来结果是一个地方没取模,凉凉. 首先有个一眼就能看出来的规律... 斐波那契数列满足$a_1, a_2, a_1+a_2, a_1+2a_2, 2a_1+3a_2, 3a_1+5a_ ...

随机推荐

  1. ES6 extends继承及super使用读书笔记

    extends 继承 extends 实现子类的继承 super() 表示父类的构造函数, 子类必须在 constructor中调用父类的方法,负责会报错. 子类的 this 是父类构造出来的, 再在 ...

  2. Centos下使用Docker部署asp.net core项目

    本文讲述 CentOS 系统 Docker 中部署 asp.net core开源项目 abp 的过程 步骤 1. 拉取 asp.net core 基础镜像 docker pull microsoft/ ...

  3. 大数据学习(一) | 初识 Hadoop

    作者: seriouszyx 首发地址:https://seriouszyx.top/ 代码均可在 Github 上找到(求Star) 最近想要了解一些前沿技术,不能一门心思眼中只有 web,因为我目 ...

  4. 裸机——RTC

    1. 首先晓得RTC的基本知识 RTC被划分到timer,但RTC是面向时间点的. 如果按照定时器的思路去思考,那么应该考虑 时间周期 和 计数值. RTC 不是面向时间点的,所以略有不同, 时间周期 ...

  5. POJ 2891 中国剩余定理(不互素)

    Strange Way to Express Integers Time Limit: 1000MS   Memory Limit: 131072K Total Submissions: 17877 ...

  6. 读懂CCS链接命令文件(.cmd)

    链接器的核心工作就是符号表解析和重定位,链接命令文件则使得编程者可以给链接器提供必要的指导和辅助信息.多数时候,由于集成开发环境的存在,开发者无需了解链接命令文件的编写,使用默认配置即可.但若需要对计 ...

  7. 購買管理(MM)

    ■購買管理■ [購買伝票]EKKO: ヘッダ EKPO: 明細 EKET: 納入日程行 EKPA: 取引先機能 EKKN: 勘定設定 EKBE: 後続伝票 EKBEH: 削除済み後続伝票履歴 [請求書 ...

  8. UCLOUD使用云主机

    购买云主机后,购买弹性ip: 设置外网防火墙,浏览器否则无法访问服务器资源: 在云主机绑定自定义的防火墙: 使用ssh登录服务器: 一般centos自带apache,没有的话安装,具体教程百度: 安装 ...

  9. 20145202 《信息安全系统设计基础》git安装

    git的安装 直接输入指令将其安装就可以了. 安装的时候要设置公钥,我不知道以前在windows上设置过的公钥是否还能用所以我就还是从新搞了一个. 验证可以连通 遇到的问题

  10. J.U.C 系列之Atomic原子类

    一 什么是原子类? 所谓原子类必然是具有原子性的类,原子性操作--原子操作,百度百科中给的定义如下 "原子操作(atomic operation)是不需要synchronized" ...