zoukankan      html  css  js  c++  java
  • [cf578F]Mirror Box

    构造如下一张无向图:

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

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

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

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

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

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

    根据矩阵树定理计算,复杂度显然是$o(k^{3})$,缩点复杂度为$o(nmlog 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 } 
    View Code
  • 相关阅读:
    id4的数据库持久化写法
    docker 加速镜像的地址收集
    mongodb 的ID转换实体要注意的地方
    net core3.0 常用封装状态码总结
    JAVA8—————StringJoiner类
    BigDecimal加减乘除
    mysql 查询奇偶数
    Java遍历Map对象的方式
    Java中List, Integer[], int[]的相互转换
    springboot 读取resources下的文件然后下载
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/14580256.html
Copyright © 2011-2022 走看看