构造如下一张无向图:

1.点集大小为$(n+1)(m+1)$,即所有格点

2.边集大小为$nm$,即所有镜子所连结的两个格点

对于一个确定的镜子状态,即可确定上图,那么来考虑什么样的图是合法的

结论:如果将这些点黑白染色,显然不存在连结黑色和白色点的边,之后合法当且仅当黑色点恰好构成生成树或白色点恰好构成生成树

由于两者不可能同时构成生成树(这意味着有$(n+1)(m+1)-2$条边,边数不足)

以黑色为例,对于一个未确定的镜子,也就是一条边是否存在,不难发现这就是一个生成树计数,对于强制存在的边预先缩点即可,由于最后至多新增$k$条边,即若缩点后连通块数多于$k+1$无解($k$为$*$个数)

根据矩阵树定理计算,复杂度显然是$o(k^{3})$,缩点复杂度为$o(nm\log nm)$,即可通过

下面考虑前面的结论,简单的说明一下:

为了方便,将最外面的一圈边界也看作镜子并连边,然后即构成了一张平面图

对于平面图中的封闭图形,显然光线无法穿过多个封闭图形,接下来我们证明一个封闭图形中恰好有一条光线,且覆盖了其中所有位置

证明比较简单,只需要找到一个与光线相邻且未被覆盖的位置,从该处引出一条光线就会导致矛盾

换言之,与边界线在同一个封闭图形内的另一个出口就是其结束的位置

这也就等价于边界上所有黑点(或白点)相邻两点连通,那么即构成一个仅含相邻两段边界线的封闭图形,同时如果不包含所有黑点,那么外面这一圈相邻两点的路径有交,必然构成一个不包含边界的封闭图形,无法被覆盖

 1 #include<bits/stdc++.h>
2 using namespace std;
3 #define N 105
4 vector<pair<int,int> >v;
5 int n,m,k,mod,a[N<<1][N<<1],pos[N*N],f[N*N];
6 char s[N][N];
7 int id(int x,int y){
8 return x*(m+1)+y+1;
9 }
10 int find(int k){
11 if (k==f[k])return k;
12 return f[k]=find(f[k]);
13 }
14 bool merge(int x,int y){
15 x=find(x),y=find(y);
16 if (x==y)return 0;
17 f[x]=y;
18 return 1;
19 }
20 int pow(int n,int m){
21 int s=n,ans=1;
22 while (m){
23 if (m&1)ans=1LL*ans*s%mod;
24 s=1LL*s*s%mod;
25 m>>=1;
26 }
27 return ans;
28 }
29 int guess(int n){
30 int ans=1;
31 for(int i=1;i<=n;i++){
32 int k=-1;
33 for(int j=i;j<=n;j++)
34 if (a[j][i]){
35 k=j;
36 break;
37 }
38 if (k<0)return 0;
39 if (k!=i){
40 ans=mod-ans;
41 for(int j=i;j<=n;j++)swap(a[i][j],a[k][j]);
42 }
43 ans=1LL*ans*a[i][i]%mod;
44 int s=pow(a[i][i],mod-2);
45 for(int j=i;j<=n;j++)a[i][j]=1LL*a[i][j]*s%mod;
46 for(int j=i+1;j<=n;j++){
47 int s=a[j][i];
48 for(int k=i;k<=n;k++)a[j][k]=(a[j][k]-1LL*s*a[i][k]%mod+mod)%mod;
49 }
50 }
51 return ans;
52 }
53 int calc(int p){
54 for(int i=0;i<=n;i++)
55 for(int j=0;j<=m;j++)
56 if ((i+j)%2==p)f[id(i,j)]=id(i,j);
57 v.clear();
58 for(int i=0;i<n;i++)
59 for(int j=0;j<m;j++)
60 if ((i+j)%2==p){
61 if (s[i][j]=='*')v.push_back(make_pair(id(i,j),id(i+1,j+1)));
62 if (s[i][j]=='\\'){
63 if (!merge(id(i,j),id(i+1,j+1)))return 0;
64 }
65 }
66 else{
67 if (s[i][j]=='*')v.push_back(make_pair(id(i,j+1),id(i+1,j)));
68 if (s[i][j]=='/'){
69 if (!merge(id(i,j+1),id(i+1,j)))return 0;
70 }
71 }
72 pos[0]=0;
73 for(int i=0;i<=n;i++)
74 for(int j=0;j<=m;j++)
75 if (((i+j)%2==p)&&(f[id(i,j)]==id(i,j)))pos[id(i,j)]=++pos[0];
76 if (pos[0]>k+1)return 0;
77 memset(a,0,sizeof(a));
78 for(int i=0;i<v.size();i++){
79 int x=pos[find(v[i].first)],y=pos[find(v[i].second)];
80 if (x<pos[0])a[x][x]=(a[x][x]+1)%mod;
81 if (y<pos[0])a[y][y]=(a[y][y]+1)%mod;
82 if ((x<pos[0])&&(y<pos[0])){
83 a[x][y]=(a[x][y]+mod-1)%mod;
84 a[y][x]=(a[y][x]+mod-1)%mod;
85 }
86 }
87 return guess(pos[0]-1);
88 }
89 int main(){
90 scanf("%d%d%d",&n,&m,&mod);
91 for(int i=0;i<n;i++){
92 scanf("%s",s[i]);
93 for(int j=0;j<m;j++)
94 if (s[i][j]=='*')k++;
95 }
96 printf("%d",(calc(0)+calc(1))%mod);
97 }

[cf578F]Mirror Box的更多相关文章

  1. [codeforces 241]C. Mirror Box

    [codeforces 241]C. Mirror Box 试题描述 Mirror Box is a name of a popular game in the Iranian National Am ...

  2. 「CF578F」 Mirror Box

    description CF578F solution 考虑转化题目的要求 1.对于任意一条边,都存在一条从界垂直射入的光线,经过反射穿过这条边. 当图中有环时,环内的边一定不满足条件,而在不存在环时 ...

  3. 矩阵树定理&BEST定理学习笔记

    终于学到这个了,本来准备省选前学来着的? 前置知识:矩阵行列式 矩阵树定理 矩阵树定理说的大概就是这样一件事:对于一张无向图 \(G\),我们记 \(D\) 为其度数矩阵,满足 \(D_{i,i}=\ ...

  4. 为 Virtual Box 中的 CentOS 6.6 配置本地DVD光盘做yum软件源

    因为virtual box 中的centos配置host-only共享win7上网,配置失败,所以只能使用Centos的 DVD 光盘来配置yum软件源.不然就没得完了. 1. 首先要在virtual ...

  5. Box/坐标/方向/Row

    1.Box, 我们在做design planning的第一步就是确定floorplan的box,也就是设计的区域.这个区域可以划分为三个边界,如下图所示: 上图中,按对应的颜色框框可以分为:Die B ...

  6. Virtual Box配置CentOS7网络(图文教程)

    之前很多次安装CentOS7虚拟机,每次配置网络在网上找教程,今天总结一下,全图文配置,方便以后查看. Virtual Box可选的网络接入方式包括: NAT 网络地址转换模式(NAT,Network ...

  7. Linux监控工具介绍系列——OSWatcher Black Box

      OSWatcher Balck Box简介 OSWatcher Black Box (oswbb)是Oracle开发.提供的一个小巧,但是实用.强大的系统工具,它可以用来抓取操作系统的性能指标,用 ...

  8. 使用packer制作vagrant centos box

    使用packer制作vagrant box:centos 制作vagrant box,网上有教程,可以自己step by step的操作.不过直接使用虚拟在VirtualBox中制作vagrant b ...

  9. 快速打造跨平台开发环境 vagrant + virtualbox + box

    工欲善其事必先利其器,开发环境 和 开发工具 就是 我们开发人员的剑,所以我们需要一个快并且好用的剑 刚开始做开发的时候的都是把开发环境 配置在 自己的电脑上,随着后面我们接触的东西越来越多,慢慢的电 ...

随机推荐

  1. JS中变量的命名规范

    命名规范 包含数字.字母.下划线和$,但 不能以数字开头 变量名严格区分大小写 变量名不能是关键字和保留字 变量名要见名知意 如果变量名有多个单词组成,推荐使用 小驼峰命名法 命名时,尽量使用英语,如 ...

  2. Spatial Analyst 工具-数学分析

    数学分析 # Process: Abs arcpy.gp.Abs_sa("", 输出栅格) # Process: Exp arcpy.gp.Exp_sa("", ...

  3. NX CAM 读取加工参数

    '取加工几何试图程序组 Function GetGemoGroup_Name(ByVal camObjectTag As NXOpen.Tag) As String Dim theGemoGroupT ...

  4. 3 Implementation: The Big Picture 实现:蓝图

    三.Implementation: The Big Picture 实现:蓝图 3.1 Layering of a .NET Solution .Net解决方案的分层 The picture belo ...

  5. 保护模式篇——TLB与CPU缓存

    写在前面   此系列是本人一个字一个字码出来的,包括示例和实验截图.由于系统内核的复杂性,故可能有错误或者不全面的地方,如有错误,欢迎批评指正,本教程将会长期更新. 如有好的建议,欢迎反馈.码字不易, ...

  6. 【原创】浅谈指针(五)const和指针

    前言 过了几个月再次更新.最近时间也不多了,快要期中考试了,暂且先少写一点吧. 本文仅在博客园发布,如在其他平台发现均为盗取,请自觉支持正版. 练习题 我们先来看几道题目.如果这几道题都不会的话,就先 ...

  7. LeetCode:回溯算法

    回溯算法 这部分主要是学习了 labuladong 公众号中对于回溯算法的讲解 刷了些 leetcode 题,在此做一些记录,不然没几天就忘光光了 总结 概述 回溯是 DFS 中的一种技巧.回溯法采用 ...

  8. Beta_Scrum Meeting_0

    日期:2021年5月26日 参会人员:cy.hcc.lsc.dxh 会议主题:为Beta阶段最早两日的开发制定目标 一.进度情况 组员 负责 两日内完成的任务 接下来两日预计完成的任务 hcc 前端 ...

  9. BUAA2020软工作业(一)——谈谈我和计算机的缘分

    项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 第一次作业-热身! 我在这个课程的目标是 进一步提高自己的编码能力,工程能力 这个作业在哪个具体方 ...

  10. find&正则表达式

    标准的正则表示式格式 常用元字符 代码 说明 . 匹配除换行符以外的任意字符 \w 匹配字母或数字或下划线 \s 匹配任意的空白符 \d 匹配数字 \b 匹配单词的开始或结束 ^ 匹配字符串的开始 $ ...