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

【算法】生成树计数(矩阵树定理)

【题解】先对定向格DFS找环判断是否无解。

然后每个点向指示方向连边,未定格向四周连边,外界作为一个点。

将所有有向边反向后,就是求根为外界的树形图的数量,生成树计数问题用矩阵树定理解决。

复杂度T*O((n*m)^3)。

考虑优化,发现重要的只有未定格的方向且k很小,所以将未定格之间的路径直接计算后只保留未定格的图,再用矩阵树定理解决。

复杂度T*O(k^3)。

注意:

1.逆元的log放在外面,否则复杂度会变成O(k^3*log k)。

2.因为要取模,高斯消元前必须全部变成正数,且矩阵每次交换两行都会使答案取反。

3.有重边,邻接矩阵不能赋值为1,有向边度数矩阵只计算入度。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=,MOD=1e9+;
const int fx[]={,,,-};
const int fy[]={,-,,};
struct edge{int v,from;}e[maxn*];
struct node{int x,y;}b[maxn];
int n,m,vis[maxn][maxn],v[maxn][maxn],tot,t[maxn][maxn],a[maxn][maxn];
char s[maxn];
bool ok;
void dfs(node u,int mark){
if(v[u.x][u.y]||u.x<||u.x>n||u.y<||u.y>m)return;
vis[u.x][u.y]=mark;
int X=u.x+fx[t[u.x][u.y]],Y=u.y+fy[t[u.x][u.y]];
if(vis[X][Y]==mark)ok=;
else if(vis[X][Y])return;
else dfs((node){X,Y},mark);
}
void insert(int u,int v){
a[v][v]++;a[u][v]--;//
}
void gcd(int a,int b,int& x,int& y){
if(!b){x=;y=;}
else{gcd(b,a%b,y,x);y-=x*(a/b);}
}
int inv(int a){
int x,y;
gcd(a,MOD,x,y);
return (x%MOD+MOD)%MOD;
}
int gauss(int n){
bool f=;
for(int i=;i<=n;i++)for(int j=;j<=n;j++)a[i][j]=(a[i][j]+MOD)%MOD;
for(int i=;i<=n;i++){
int r=i;
for(int j=i+;j<=n;j++)if(a[j][i]>a[r][i])r=j;
if(r!=i){for(int j=i;j<=n+;j++)swap(a[i][j],a[r][j]);f^=;}
int w=inv(a[i][i]);//
for(int j=i+;j<=n;j++){
for(int k=n+;k>=i;k--){
a[j][k]=(a[j][k]-1ll*a[j][i]*w%MOD*a[i][k]%MOD+MOD)%MOD;//
}
}
}
int ans=f?MOD-:;
for(int i=;i<=n;i++)ans=1ll*ans*a[i][i]%MOD;
return ans;//
}
int main(){
int T;scanf("%d",&T);
while(T--){
memset(v,,sizeof(v));
memset(vis,,sizeof(vis));
memset(a,,sizeof(a));
tot=;
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++){
scanf("%s",s+);
for(int j=;j<=m;j++){
if(s[j]=='U')t[i][j]=;
if(s[j]=='D')t[i][j]=;
if(s[j]=='L')t[i][j]=;
if(s[j]=='R')t[i][j]=;
if(s[j]=='.'){v[i][j]=++tot;b[tot]=(node){i,j};}
}
}
ok=;
for(int i=;i<=n;i++){
for(int j=;j<=m;j++)if(!vis[i][j])dfs((node){i,j},(i-)*m+j);
if(!ok)break;
}
if(!ok){puts("");continue;}
tot++;
for(int i=;i<tot;i++){
int x=b[i].x,y=b[i].y;
for(int j=;j<;j++){
int X=x+fx[j],Y=y+fy[j];bool yes=;
while(X>=&&X<=n&&Y>=&&Y<=m){
if(v[X][Y]){if(v[X][Y]!=i)insert(v[X][Y],i);yes=;break;}
else{
int o1=fx[t[X][Y]],o2=fy[t[X][Y]];
X+=o1;Y+=o2;
}
}
if(!yes)insert(tot,i);
}
}
printf("%d\n",gauss(tot-));
}
return ;
}

【LibreOJ】#6259. 「CodePlus 2017 12 月赛」白金元首与独舞的更多相关文章

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

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

  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. 【LIbreOJ】#6256. 「CodePlus 2017 12 月赛」可做题1

    [题意]定义一个n阶正方形矩阵为“巧妙的”当且仅当:任意选择其中n个不同行列的数字之和相同. 给定n*m的矩阵,T次询问以(x,y)为左上角的k阶矩阵是否巧妙.n,m<=500,T<=10 ...

  6. 【LibreOJ】#6257. 「CodePlus 2017 12 月赛」可做题2

    [题意]数列满足an=an-1+an-2,n>=3.现在a1=i,a2=[l,r],要求满足ak%p=m的整数a2有多少个.10^18. [算法]数论(扩欧)+矩阵快速幂 [题解]定义fib(i ...

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

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

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

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

  9. 「CodePlus 2017 12 月赛」火锅盛宴

    n<=100000种食物,给每个食物煮熟时间,有q<=500000个操作:在某时刻插入某个食物:查询熟食中编号最小的并删除之:查询是否有编号为id的食物,如果有查询是否有编号为id的熟食, ...

随机推荐

  1. 使用Logstash同步数据至Elasticsearch,Spring Boot中集成Elasticsearch实现搜索

    安装logstash.同步数据至ElasticSearch 为什么使用logstash来同步,CSDN上有一篇文章简要的分析了以下几种同步工具的优缺点:https://blog.csdn.net/la ...

  2. 复利计算C语言转java的相关代码

    static void principal()// 计算本金 { int N, m; double i, F, P; System.out.printf("复利终值:"); F = ...

  3. UEditor前端配置项说明

    UEditor 的配置项分为两类:前端配置项 和 后端配置项 后端配置项具体看这个文档L:后端配置项说明 本文档介绍如何通过设置前端配置项,定制编辑器的特性,配置方法主要通过修改ueditor.con ...

  4. addEventListener和attachEvent区别

    addEventListener()是标准的绑定事件监听函数的方法,是W3C所支持的,Chrome.FireFox.Opera.Safari.IE9.0及其以上版本都支持该函数:但是,IE8.0及其以 ...

  5. BZOJ4881 线段游戏(二分图+树状数组/动态规划+线段树)

    相当于将线段划分成两个集合使集合内线段不相交,并且可以发现线段相交等价于逆序对.也即要将原序列划分成两个单增序列.由dilworth定理,如果存在长度>=3的单减子序列,无解,可以先判掉. 这个 ...

  6. java学习2-webserver测试工具soapUI使用

    file-->new soap project-->输入project Name(随便)输入 WSDL地址,其他默认,点ok展开左侧加载的项目下的方法名,双击Request ,右侧出现测试 ...

  7. 【BZOJ4129】Haruna’s Breakfast(树上莫队)

    [BZOJ4129]Haruna's Breakfast(树上莫队) 题面 BZOJ Description Haruna每天都会给提督做早餐! 这天她发现早饭的食材被调皮的 Shimakaze放到了 ...

  8. windows 10上利用Microsoft RTF文件(CVE-2017-0199)进行攻击

    Microsoft Word下的恶意RTF文件容易被收到攻击,在本文中,我们使用python脚本对Microsoft Word 2013进行oday攻击演示,该脚本会生成恶意的.rtf文件,并提供目标 ...

  9. Java之基础20160806

    注意这里介绍的JAVA基础是指你对C语言已经比较熟练或者有一定基础了,再学习如下这知识就会比较快. 1.JAVA也是从MAIN开始执行,但是要先定义类,文件名要与类名一致并且类名首字母要大写,同时JA ...

  10. 批量修改历史commit的用户名user.name邮箱user.email

    配置当前的用户名邮箱可以当前项目配置或者全局配置. 仅当前项目配置: git config user.name 'your-user-name' git config user.email 'your ...