【AGC003F】Fraction of Fractal
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 <cstdio>
#include <cstring>
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<m)
lh+=(str[i][j]=='#'&&str[i][j+1]=='#');
if(i<n)
lv+=(str[i][j]=='#'&&str[i+1][j]=='#');
}
if(hcnt&&vcnt) return 1;
else if(!hcnt&&!vcnt) return 2;
if(hcnt){
swap(hcnt,vcnt);
swap(lh,lv);
}
return 3;
}
void fillMatrix(){
O=Mat(1,3);
O.a[1][1]=blacksum; O.a[1][2]=lv; O.a[1][3]=vcnt;
T=Mat(3,3);
T.a[1][1]=blacksum;
T.a[2][2]=blacksum; T.a[3][2]=lv;
T.a[3][3]=vcnt;
}
Mat mat_fmi(Mat x,ll y){
Mat res=Mat(x.n,x.n);
res.setUnit();
for(;y;x=x*x,y>>=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;
}
【AGC003F】Fraction of Fractal的更多相关文章
- 【leetcode】Fraction to Recurring Decimal
Fraction to Recurring Decimal Given two integers representing the numerator and denominator of a fra ...
- 【LeetCode】数学(共106题)
[2]Add Two Numbers (2018年12月23日,review) 链表的高精度加法. 题解:链表专题:https://www.cnblogs.com/zhangwanying/p/979 ...
- 【LeetCode】哈希表 hash_table(共88题)
[1]Two Sum (2018年11月9日,k-sum专题,算法群衍生题) 给了一个数组 nums, 和一个 target 数字,要求返回一个下标的 pair, 使得这两个元素相加等于 target ...
- HDU 5912 Fraction 【模拟】 (2016中国大学生程序设计竞赛(长春))
Fraction Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Su ...
- 【LeetCode】166. Fraction to Recurring Decimal 解题报告(Python)
[LeetCode]166. Fraction to Recurring Decimal 解题报告(Python) 标签(空格分隔): LeetCode 作者: 负雪明烛 id: fuxuemingz ...
- 【LeetCode】592. Fraction Addition and Subtraction 解题报告(Python)
[LeetCode]592. Fraction Addition and Subtraction 解题报告(Python) 标签(空格分隔): LeetCode 作者: 负雪明烛 id: fuxuem ...
- 【Codeforces Round #433 (Div. 2) A】Fraction
[链接]h在这里写链接 [题意] 在这里写题意 [题解] 枚举分子从高到低就好. 这样得到的一定是最大的. (可以约分没错,但是约分过后和就不是n了,所以不会有错的) [错的次数] 0 [反思] 在这 ...
- 【BZOJ1672】[Usaco2005 Dec]Cleaning Shifts 清理牛棚 动态规划
[BZOJ1672][Usaco2005 Dec]Cleaning Shifts Description Farmer John's cows, pampered since birth, have ...
- 【MySQL】TokuDB引擎初探(MySQL升级为Percona,MySQL升级为MariaDB)
参考:http://blog.sina.com.cn/s/blog_4673e6030102v46l.html 参考:http://hcymysql.blog.51cto.com/5223301/14 ...
随机推荐
- d-ary heap实现一个快速的优先级队列(C#)
d-ary heap简介: d-ary heap 是泛化版本的binary heap(d=2),d-ary heap每个非叶子节点最多有d个孩子结点. d-ary heap拥有如下属性: 类似comp ...
- 布线问题 (NYOJ38)
布线问题 时间限制:1000 ms | 内存限制:65535 KB 难度:4 描述 南阳理工学院要进行用电线路改造,现在校长要求设计师设计出一种布线方式,该布线方式需要满足以下条件:1.把所有 ...
- 【LeetCode算法题库】Day2:Median of Two Sorted Arrays & Longest Palindromic Substring & ZigZag Conversion
[Q4] There are two sorted arrays nums1 and nums2 of size m and n respectively. Find the median of th ...
- 初试Shell脚本
背景 临上线前测试比较努力,遇到闪退或者其他问题,会把日志包打给我,由于app内存限制,目前每次打包都是1m大小,所以有时查找问题的上下文比较吃力.同时由于日志比较多,根据关键词过滤的需求越来越重要. ...
- [笔试]CVTE 2019提前批 Windows应用开发笔试
不定项选择(x20) 数据结构 以abcdefg的顺序入栈,不可能出现的出栈顺序 一棵二叉树给出中序遍历和后序遍历结果,求左子树的节点数 操作系统 Linux中用什么指令可以找到文件中所有以" ...
- Protocol buffer的使用案例
Protocolbuffer(以下简称PB)是google 的一种数据交换的格式,它独立于语言,独立于平台.google 提供了多种语言的实现:java.c#.c++.go 和 python,每一种实 ...
- Git----02本地仓库进行文件添加&修改&删除&查看
一.将新文件上传到本地仓库----使用小乌龟工具 1.1.将文件添加到暂存区 进入仓库目录,创建文件,添加暂存区 1.2.将文件添加到本地仓库 选中已经添加到暂存区的文件,进行提交 二.查看本 ...
- Oracle VM VirtualBox 无法卸载 更新 和修复
好久没更新Oracle VM VirtualBox 突然发现不能更新了 提示要某个msi文件,回想起来好像是被某个清理垃圾的软件清理掉了. 于是根据提示的版本号网上搜了种子又把安装包下载回来 在命令行 ...
- 在NodeJS中使用Redis缓存数据
Redis数据库采用极简的设计思想,最新版的源码包还不到2Mb.其在使用上也有别于一般的数据库. node_redis redis驱动程序多使用 node_redis 此模块可搭载官方的 hiredi ...
- easyui panel异步获取后台数据在前台显示
我在使用easyui的时候,想做一个向下图所示的效果,这个panel的样式已经做好了,想从后台异步获取json数据,然后填入到文本框中,不知道哪位大神能给点指导?万分感谢! 放入表单中,使用form对 ...