• [loj3246]Cave Paintings


    题中所给的判定条件似乎比较神奇,那么用严谨的话来说就是对于两个格子(x,y)和(x',y'),如果满足:
    1.$xle x'$;
    2.从(x,y)通过x,x+1,……,n行,允许向四个方向走,不允许经过石头的位置/画外,可以到达(x',y')
    若(x,y)有水,那么(x',y')也有水
    这个性质似乎并没有什么用,考虑对于$x=x'$的情况,相当于这些y必须都是同一个状态,容易想到一个思路:从下往上进行枚举,用一个并查集维护这一行的所有点,然后将这一行与下一行相邻的点连起来,形成这一行的并查集
    通过并查集,可以将同一行内在同一个并查集内的点缩起来,并向下面的点连边,容易发现一定是森林
    (证明:如果存在上面两个点同时指向其中一个点,那么这两个点肯定会缩起来)
    那么题中的条件就有意义了:相当于如果一个点的根选择了1,那么整个子树都必须选1,求方案数,树形dp即可

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 1005
     4 #define mod 1000000007
     5 int V,n,m,ans,f[N*N],dp[N*N],bl[N][N];
     6 char s[N][N];
     7 int find(int k){
     8     if (k==f[k])return k;
     9     return f[k]=find(f[k]);
    10 }
    11 void merge(int x,int y){
    12     if (find(x)==find(y))return;
    13     dp[find(y)]=1LL*dp[find(x)]*dp[find(y)]%mod; 
    14     f[find(x)]=find(y);
    15 }
    16 int main(){
    17     scanf("%d%d",&n,&m);
    18     for(int i=1;i<=n;i++)scanf("%s",s[i]);
    19     for(int i=n;i;i--){
    20         int las=V;
    21         for(int j=1;j<m-1;j++)
    22             if (s[i][j]=='.'){
    23                 if (s[i][j-1]=='#'){
    24                     dp[++V]=1;
    25                     f[V]=V;
    26                 }
    27                 bl[i][j]=V;
    28                 if (s[i+1][j]=='.')merge(bl[i+1][j],V);
    29             }
    30         for(int j=las+1;j<=V;j++)
    31             if (find(j)==j)dp[j]=(dp[j]+1)%mod;
    32     }
    33     ans=1;
    34     for(int i=1;i<=V;i++)
    35         if (find(i)==i)ans=1LL*ans*dp[i]%mod;
    36     printf("%d",ans);
    37 }
    View Code
  • 相关阅读:
    jq获取地址中的参数的值
    移动设备分辨率
    随机生成颜色
    小程序轮播图
    JavaScript中的constructor、instanceof、isPrototypeOf、typeof以及hasOwnProperty
    call()和apply()函数
    行内元素和块级元素
    js跳出循环的方法区别(break,continue,return)
    js 的四种设计模式的优缺点
    常见浏览器兼容性问题与解决方案
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/12244092.html
Copyright © 2020-2023  润新知