当前位置: 首页 > news >正文

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

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

试题描述

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

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

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

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


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

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

QAQ

元首已经设计好了大部分格子的标识。元首用字符 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;
}

转载于:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/8111259.html

相关文章:

  • EasyPlayerPro windows播放器本地音频播放音量控制实现
  • SQL Server索引内部结构:SQL Server索引的阶梯级别10
  • apache ant 修改java版本 方法之一
  • bzoj1911[Apio2010]特别行动队 斜率优化dp
  • 通俗理解webService及.net中的使用方法
  • PHP后门的eval类和system类 函数到底有哪些区别
  • mint-ui 填坑之路
  • 秒懂Vuejs、Angular、React原理和前端发展历史
  • Java定时器应用
  • 模型分离(选做)
  • 游戏全区全服和分区分服 QQ斗地主的设计
  • 【习题 7-7 UVA-12558】Egyptian Fractions (HARD version)
  • 仿腾讯固定导航栏
  • window进行缩放时左侧菜单高度随之变化
  • 如何将pdf文件的英文翻译成中文
  • [deviceone开发]-do_Webview的基本示例
  • [译]如何构建服务器端web组件,为何要构建?
  • 【许晓笛】 EOS 智能合约案例解析(3)
  • angular2开源库收集
  • - C#编程大幅提高OUTLOOK的邮件搜索能力!
  • CSS相对定位
  • gcc介绍及安装
  • npx命令介绍
  • python 学习笔记 - Queue Pipes,进程间通讯
  • Spring技术内幕笔记(2):Spring MVC 与 Web
  • Travix是如何部署应用程序到Kubernetes上的
  • ViewService——一种保证客户端与服务端同步的方法
  • 如何在GitHub上创建个人博客
  • 使用权重正则化较少模型过拟合
  • 学习使用ExpressJS 4.0中的新Router
  • 一道闭包题引发的思考
  • 云栖大讲堂Java基础入门(三)- 阿里巴巴Java开发手册介绍
  • const的用法,特别是用在函数前面与后面的区别
  • ​批处理文件中的errorlevel用法
  • ​软考-高级-系统架构设计师教程(清华第2版)【第20章 系统架构设计师论文写作要点(P717~728)-思维导图】​
  • #{}和${}的区别?
  • #我与Java虚拟机的故事#连载03:面试过的百度,滴滴,快手都问了这些问题
  • (01)ORB-SLAM2源码无死角解析-(66) BA优化(g2o)→闭环线程:Optimizer::GlobalBundleAdjustemnt→全局优化
  • (9)YOLO-Pose:使用对象关键点相似性损失增强多人姿态估计的增强版YOLO
  • (Redis使用系列) Springboot 使用redis实现接口幂等性拦截 十一
  • (windows2012共享文件夹和防火墙设置
  • (翻译)Quartz官方教程——第一课:Quartz入门
  • (排序详解之 堆排序)
  • (十五)Flask覆写wsgi_app函数实现自定义中间件
  • (转)机器学习的数学基础(1)--Dirichlet分布
  • (总结)Linux下的暴力密码在线破解工具Hydra详解
  • .NET CF命令行调试器MDbg入门(一)
  • .net web项目 调用webService
  • .NET面试题(二)
  • /etc/motd and /etc/issue
  • @31省区市高考时间表来了,祝考试成功
  • @data注解_一枚 架构师 也不会用的Lombok注解,相见恨晚
  • @select 怎么写存储过程_你知道select语句和update语句分别是怎么执行的吗?
  • [ solr入门 ] - 利用solrJ进行检索
  • [Android] Android ActivityManager