zoukankan      html  css  js  c++  java
  • [agc003F]Fraction of Fractal

    Description

    传送门

     Solution

     本篇博客思路来自大佬的博客(侵删)。

    我们定义如果网格的第一行和最后一行的第i列都为黑色,则它是一个上下界接口。左右界接口定义同上。

    如果上下界接口和左右界接口都为0个,则答案为节点数^(k-1)。或者上下界接口和左右界接口都存在,则答案为1(就只有一个联通块了啊)。

    将以上两种情况特判后,我们目前的网格要么只有上下界接口,要么只有左右界接口。我们只探讨前者。

    对于k=2的分形(如果k<2特判就好),我们将1级分形看作一个节点(以下的点都是指1级分形,边同理),如果它与其他节点连通则视为将两个节点之间加一条边。

    因为我们的网格只有上下界接口,所以2级分形事实上是由若干条链构成。以此类推,k级分形也是如此。

    将链看成树,我们就可以运用森林的性质:树的个数等于总点数减去总边数。(这个性质是真的牛啊我自己完全想不到),即最后联通块的个数为总点数减去总边数。

    考虑求总边数:

      记原图中节点总数为all。

      定义若a[i][j]与a[i+1][j]都为黑点则这是一个上下接口,(注意不是上下界接口),记其个数为usb。

      记上下界接口个数为u。

      设Ek为k级分形的边数。

        边界E2=usb   递推式为 Ek=Ek-1*all+usb*uk-1

    至于总点数(这里的点还是指1级分形)。。快速幂就好了。

    Code

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    using namespace std;
    const int mod=1e9+7;
    typedef long long ll;
    char ch[1010];
    int a[1010][1010],h,w,up_down,left_right,cnt,usb;//cnt:黑点总数,usb:原图内总接口数 
    long long _pow; 
    ll ksm(ll x,long long k)
    {
        ll ans=1;
        while (k)
        {
            if (k&1)ans=ans*x%mod;
            k>>=1;
            x=x*x%mod;
        }
        return ans;
    }
    struct Matrix
    {
        ll t[4][4];
        friend Matrix operator *(Matrix x,Matrix y)
        {
            Matrix z;
            memset(z.t,0,sizeof(z.t));
            for (int i=0;i<2;i++) 
                for (int j=0;j<2;j++)
                    for (int k=0;k<2;k++)
                        z.t[i][j]=(z.t[i][j]+x.t[i][k]*y.t[k][j])%mod;
            return z;
        }
        friend Matrix operator ^(Matrix x,long long k)
        {
            Matrix ans;
            memset(ans.t,0,sizeof(ans.t));
            ans.t[0][0]=ans.t[1][1]=1;
            while (k)
            {
                if (k&1) ans=ans*x;
                k>>=1;
                x=x*x;
            }
            return ans;
        }
    }A,B;
    int main()
    {
        scanf("%d%d%lld",&h,&w,&_pow);
        if (_pow<=1) {printf("1");return 0;}
        for (int i=1;i<=h;i++)
        {
            scanf("%s",ch+1);
            for (int j=1;j<=w;j++) 
            {
                a[i][j]=(ch[j]=='#');
                if (a[i][j]) cnt++;
            }
        }    
        for (int i=1;i<=w;i++) 
            if (a[1][i]&&a[h][i]) up_down++;
        for (int i=1;i<=h;i++)
            if (a[i][1]&&a[i][w]) left_right++;
        if (!up_down&&!left_right)
        {
            printf("%lld",ksm(cnt,_pow-1));return 0;
        }
        if (up_down&&left_right) 
        {
            printf("1");return 0;
        }
        for (int i=1;i<=h;i++)
            for (int j=1;j<=w;j++)
            {
                if (a[i][j]&&a[i][j+1]&&left_right) usb++;
                if (a[i][j]&&a[i+1][j]&&up_down) usb++;
            }
        A.t[0][0]=cnt;A.t[0][1]=usb;A.t[1][1]=max(up_down,left_right);
        A=A^(_pow-2);
        ll ans;ans=A.t[0][0]*usb%mod+A.t[0][1]*max(up_down,left_right)%mod;
        ans%=mod;
        printf("%lld",(ksm(cnt,_pow-1)-ans+mod)%mod);
    }
  • 相关阅读:
    织梦调用所有栏目一级二级三级和无限级栏目输出
    织梦添加自定义独立模型缩略图字段官方的一个BUG
    织梦搜索结果增加dede:type、dede:arclist、dede:channelartlist、dede:tag等标签支持
    织梦搜索指定多个栏目的文档
    POJ 1001
    #207 Div.2 B. Flag Day
    sublime Text 2 配置 C++ 编译环境
    1011. 复数类
    1008. 二哥买期货
    MySQL/mariadb知识点——视图管理语句
  • 原文地址:https://www.cnblogs.com/coco-night/p/9490195.html
Copyright © 2011-2022 走看看