zoukankan      html  css  js  c++  java
  • [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
    ", solve());
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    基于 mysql 异步驱动的非阻塞 Mybatis【待验证】
    Hive SQL优化方式及使用技巧
    使用Guava-RateLimiter限流控制qps
    hive 时间戳函数之unix_timestamp,from_unixtime
    Hive实现自增列的两种方法
    shell 下 urlencode/urldecode 编码/解码的方法
    awk使用shell变量,shell获取awk中的变量值
    shell脚本删除远程过期文件
    linux下多进程同时操作文件
    hive学习----Hive表的创建
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/8111259.html
Copyright © 2011-2022 走看看