首页 > 其他 > 详细

[agc003F]Fraction of Fractal

时间:2018-08-16 22:08:12      阅读:202      评论:0      收藏:0      [点我收藏+]

Description

        Snuke从他的母亲那里得到了生日礼物——一个网格。网格有HW列。每个单元格都是黑色或白色。所有黑色单元格都是四联通的,也就是说,只做水平或垂直移动且只经过黑色单元格即可从任何黑色单元格移动到任何其他黑色单元格。
        第i行第j列的单元格的颜色由字符si,j表示。如果si,j是 #,该单元格为黑色;如果si,j是 .,该单元格为白色。至少一个单元格是黑色的。
        我们定义「分形」如下:0级分形是一个 1×1的黑色单元格.k级分形由H行W列的k-1级分形按照 Snuke 的网格的样式拼成:与Snuke 网格中的黑色单元格对应的位置是一个k-1级分形;与Snuke网格中的白色单元格对应的位置是一个单元格全部为白色,尺寸与k-1级分形相同的网格。
        您将得到 Snuke的网格的描述和整数 K。请求出K级分形中黑色单元格组成的连通分量数,模109+7

 

本题思路主要来自于大佬的blog:https://www.cnblogs.com/RogerDTZ/p/9487372.html

我们定义如果网格的第一行和最后一行的第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级分形)。。快速幂就好了。

#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);
}

 

 

 

[agc003F]Fraction of Fractal

原文:https://www.cnblogs.com/coco-night/p/9490195.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!