博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【AGC003F】Fraction of Fractal
阅读量:5064 次
发布时间:2019-06-12

本文共 3117 字,大约阅读时间需要 10 分钟。

Description

  

​  
  
​  
  

Solution

  

​   神题。
  
​   定义一个上边界或下边界的格子为”上下接口“,当且仅当上下边界该位置的格子都是黑色的。
  
​   ”左右接口“同理。
  
  首先特判掉\(k\)小于等于1的情况,答案都是1。
  
​   然后特判掉两种情况:上下接口和左右接口同时存在时,答案显然为1;二者皆不存在时,答案就是\(s^{k-1}\),其中\(s\)为给定网格的黑格子数目。
  
​   所以接下来我们考虑的问题是:\(k\ge 2\),且仅存在上下接口或左右接口。现在我们只考虑前者的情况,后者可以通过旋转原网格来达到同样的效果。
  
​   首先来观察2级分形的结构:我们不妨把其中的每一块1级分形看做一个节点,如果两个相邻1级分形可以互相连通,则视为将其对应节点之间连一条。由此我们对2级分形构造出一张图。
  
​   对于3级及其以上分形,节点的定义不再扩展,依然是1级分形、表示1级分形之间是否连通。
  
​   可以发现,由于当前只存在上下接口,因此2级分形的图是由若干条竖直方向的链构成的。推广一下,就会发现,对于\(k\)级分形\((k \ge 2)\)对应的图,它们都有着这个性质。
  
​   将链看成树,我们就可以运用森林的性质:树的个数等于总点数减去总边数。则连通块个数等于总点数减去总边数。
  
​   记\(a\)表示给定网格样式中,上下两个格子都是黑色的位置有多少,即\(\sum [map_{i,j}=map_{i+1,j}='\#']\)
  
​   记\(b\)表示上下接口的个数(同一列的两个接口只算1个)
  
​   记\(V_k\)表示\(k\)级分形图中的个数,\(E_k\)表示\(k\)级分形图中的条数。则有递推式:
  
    \(V_2=s\)\(E_2=a\)

    \(V_k=V_{k-1}*s\)\(E_k=E_{k-1}*s+ab^{k-2}\)

    
  其中\(V\)的递推显然,而\(E\)的含义则是:每个低级分形中边个数乘上扩增倍数,加上低级分形在组合成高级分形时通过上下接口新产生的边数。注意\(b\)之所以含有一个幂形式,是因为随着分形级数的不断扩增,上下接口的数量也在不断增长。
  
  使用矩阵快速幂计算就做完了。
  
  
  

Code

  

#include 
#include
using namespace std;typedef long long ll;const int N=1005;const int MOD=1e9+7;int n,m,blacksum;ll kk;char str[N][N];int map[N][N];int hcnt,vcnt,lh,lv;inline void plus(int &x,int y){ x=(x+y>=MOD)?(x+y-MOD):x+y;}inline void swap(int &x,int &y){ x^=y^=x^=y;}inline int fmi(int x,ll y){ int res=1; for(;y;x=1LL*x*x%MOD,y>>=1) if(y&1) res=1LL*res*x%MOD; return res;}struct Mat{/*{
{
{*/ int n,m; int a[4][4]; Mat(){ memset(a,0,sizeof a); } Mat(int _n,int _m){ n=_n; m=_m; clear(); } void setUnit(){ if(n!=m) return; for(int i=1;i<=n;i++) a[i][i]=1; } void clear(){ for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) a[i][j]=0; } friend Mat operator * (Mat u,Mat v){ Mat res=Mat(u.n,v.m); for(int i=1;i<=u.n;i++) for(int j=1;j<=v.m;j++) for(int k=1;k<=u.m;k++) //(res.a[i][j]+=1LL*u.a[i][k]*v.a[k][j]%MOD)%=MOD; plus(res.a[i][j],1LL*u.a[i][k]*v.a[k][j]%MOD); return res; }}O,T;/*}}}*/void readData(){ scanf("%d%d%lld",&n,&m,&kk); for(int i=1;i<=n;i++){ scanf("%s",str[i]+1); for(int j=1;j<=m;j++) blacksum+=(str[i][j]=='#'); }}int getTypeAndInit(){ for(int i=1;i<=n;i++) hcnt+=(str[i][1]=='#'&&str[i][m]=='#'); for(int j=1;j<=m;j++) vcnt+=(str[1][j]=='#'&&str[n][j]=='#'); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ if(j
>=1) if(y&1) res=res*x; return res;}void solve(){ fillMatrix(); T=mat_fmi(T,kk-2); O=O*T; int ans=O.a[1][1]-O.a[1][2]; printf("%d\n",ans<0?ans+MOD:ans);}int main(){ readData(); if(kk<=1){ puts("1"); return 0; } int type=getTypeAndInit(); if(type==1)//whole puts("1"); else if(type==2)//isolated printf("%d\n",kk==0?1:fmi(blacksum,kk-1)); else solve(); return 0;}

转载于:https://www.cnblogs.com/RogerDTZ/p/9487372.html

你可能感兴趣的文章
python使用上下文对代码片段进行计时,非装饰器
查看>>
js中比较实用的函数用法
查看>>
安装预览版镜像后无法检测到预览版更新的解决方案
查看>>
【bzoj5099】[POI2018]Pionek 双指针法
查看>>
别让安全问题拖慢了 DevOps!
查看>>
JAR打包和运行
查看>>
session如何保存在专门的StateServer服务器中
查看>>
react展示数据
查看>>
测试计划
查看>>
idea设置自定义图片
查看>>
[高级]Android多线程任务优化1:探讨AsyncTask的缺陷
查看>>
选择器
查看>>
rownum 的使用
查看>>
Mysql与Oracle 的对比
查看>>
MVC系列博客之排球计分(三)模型类的实现
查看>>
npm安装
查看>>
阅读笔记02
查看>>
2019年春季学期第二周作业
查看>>
2014北邮计算机考研复试上机题解(上午+下午)
查看>>
mySQL 教程 第7章 存储过程和函数
查看>>