@atcoder - AGC003F@ Fraction of Fractal
@description@
给定一个 H*W 黑白格图,保证黑格四连通。
定义分形如下:0 级分形是一个 1*1 的黑格;通过将第 k 级分形中的白格替换成 H*W 的全白,黑格替换成题目所给的 H*W 格图得到第 k + 1 级分形。
求第 K 级分形中黑格的四连通块个数。
@solution@
最好先特判 K = 0 的情况。
如果存在一行最左最右都是黑格,且存在一列最上最下都是黑格,则黑格始终形成 1 个连通块。
如果不存在一行最左最右都是黑格,且不存在一列最上最下都是黑格,则连通块个数每次都呈指数增长。
如果记 cnt = 原图中黑格数量,则 ans = cnt^K。
否则,我们讨论存在一行最左最右都是黑格(另一种情况同理)。
记 g(i, j) 表示 j 个 i 级分形拼成一行,黑格形成的连通块数量,我们可以在 g(i, ...) 与 g(i - 1, ...) 之间建立转移关系。
讨论每一行是否全为黑格。如果不是,求每一行最左边往右延伸的最长连续黑格,最右边往左延伸的最长连续黑格,中间那些不与最左/右边有关的黑格连续段,利用这些信息进行转移。
具体怎么转移比较复杂,此处不提。
但是注意到 g 的第二维可能超大。不妨猜测 g(i, j) = k(i)*j + b(i),代入转移式发现成立。
于是就变成了 k(i), b(i) 与 k(i - 1), b(i - 1) 之间的转移。剩下的直接使用矩阵幂即可。
@accepted code@
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 1000;
const int MOD = int(1E9) + 7;
inline int add(int x, int y) {return (x + y >= MOD ? x + y - MOD : x + y);}
inline int sub(int x, int y) {return (x - y < 0 ? x - y + MOD : x - y);}
inline int mul(int x, int y) {return 1LL * x * y % MOD;}
int pow_mod(int b, ll p) {
int ret = 1;
for(ll i=p;i;i>>=1,b=mul(b,b))
if( i & 1 ) ret = mul(ret, b);
return ret;
}
struct matrix{
int a[2][2];
friend matrix operator * (matrix A, matrix B) {
matrix C;
C.a[0][0] = add(mul(A.a[0][0], B.a[0][0]), mul(A.a[0][1], B.a[1][0]));
C.a[0][1] = add(mul(A.a[0][0], B.a[0][1]), mul(A.a[0][1], B.a[1][1]));
C.a[1][0] = add(mul(A.a[1][0], B.a[0][0]), mul(A.a[1][1], B.a[1][0]));
C.a[1][1] = add(mul(A.a[1][0], B.a[0][1]), mul(A.a[1][1], B.a[1][1]));
return C;
}
};
matrix mpow(matrix A, ll p) {
matrix ret; ret.a[0][0] = ret.a[1][1] = 1, ret.a[0][1] = ret.a[1][0] = 0;
for(ll i=p;i;i>>=1,A=A*A)
if( i & 1 ) ret = ret*A;
return ret;
}
int a, b[MAXN + 5], c[MAXN + 5], d[MAXN + 5];
char s[MAXN + 5][MAXN + 5], t[MAXN + 5][MAXN + 5];
int main() {
int H, W; ll K; scanf("%d%d%lld", &H, &W, &K);
for(int i=0;i<H;i++)
scanf("%s", s[i]);
if( K == 0 ) {
puts("1");
return 0;
}
bool f1 = false, f2 = false;
for(int i=0;i<H;i++)
if( s[i][0] == '#' && s[i][W-1] == '#' ) {
f1 = true;
break;
}
for(int i=0;i<W;i++)
if( s[0][i] == '#' && s[H-1][i] == '#' ) {
f2 = true;
break;
}
if( f1 && f2 )
puts("1");
else if( (!f1) && (!f2) ) {
int cnt = 0;
for(int i=0;i<H;i++)
for(int j=0;j<W;j++)
cnt += (s[i][j] == '#');
printf("%d\n", pow_mod(cnt, K - 1));
}
else {
if( f2 ) {
for(int i=0;i<H;i++)
for(int j=0;j<W;j++)
t[j][i] = s[i][j];
swap(H, W);
for(int i=0;i<H;i++)
for(int j=0;j<W;j++)
s[i][j] = t[i][j];
}
for(int i=0;i<H;i++) {
bool flag = true;
for(int j=0;j<W;j++)
if( s[i][j] == '.' ) {
flag = false;
break;
}
if( flag ) a++;
else {
int l, r;
for(int j=0;j<W;j++)
if( s[i][j] == '.' ) {
l = j;
break;
}
for(int j=W-1;j>=0;j--)
if( s[i][j] == '.' ) {
r = j;
break;
}
int lst = l;
for(int j=l;j<=r;j++) {
if( s[i][j] == '.' ) {
if( lst != j ) b[j-lst]++;
lst = j + 1;
}
}
c[i] = l, d[i] = W - r - 1;
}
}
matrix A;
A.a[0][0] = mul(a, W), A.a[1][1] = a, A.a[0][1] = A.a[1][0] = 0;
for(int j=1;j<=W;j++)
A.a[0][0] = add(A.a[0][0], mul(b[j], j)), A.a[0][1] = add(A.a[0][1], b[j]);
for(int j=0;j<H;j++) {
if( c[j] ) A.a[1][0] = add(A.a[1][0], c[j]), A.a[1][1] = add(A.a[1][1], 1);
if( d[j] ) A.a[1][0] = add(A.a[1][0], d[j]), A.a[1][1] = add(A.a[1][1], 1);
if( c[j] + d[j] ) {
A.a[0][0] = add(A.a[0][0], c[j] + d[j]), A.a[0][1] = add(A.a[0][1], 1);
A.a[1][0] = sub(A.a[1][0], c[j] + d[j]), A.a[1][1] = sub(A.a[1][1], 1);
}
}
A = mpow(A, K - 1);
printf("%d\n", add(A.a[0][1], A.a[1][1]));
/*
int x = 0, y = 1;
for(int i=2;i<=K;i++) {
int x1 = mul(a, mul(x, W)), y1 = mul(a, y);
for(int j=1;j<=W;j++)
x1 = add(x1, mul(b[j], add(mul(x, j), y))); // x1 += b[j]*(x*j + y)
for(int j=0;j<H;j++) {
if( c[j] ) y1 = add(y1, add(mul(x, c[j]), y)); // y1 += c[j]*x + y
if( d[j] ) y1 = add(y1, add(mul(x, d[j]), y)); // y1 += d[j]*x + y
if( c[j] + d[j] ) {
x1 = add(x1, add(mul(x, c[j] + d[j]), y)); // x1 += (c[j]+d[j])*x + y
y1 = sub(y1, add(mul(x, c[j] + d[j]), y)); // y1 -= (c[j]+d[j])*x + y
}
}
x = x1, y = y1;
}
printf("%d\n", add(x, y));
*/
}
}
@details@
感觉分形题真有意思。
@atcoder - AGC003F@ Fraction of Fractal的更多相关文章
- [agc003F]Fraction of Fractal
Description 传送门 Solution 本篇博客思路来自大佬的博客(侵删). 我们定义如果网格的第一行和最后一行的第i列都为黑色,则它是一个上下界接口.左右界接口定义同上. 如果上下界接口和 ...
- [AGC003F] Fraction of Fractal 矩阵快速幂
Description SnukeSnuke从他的母亲那里得到了生日礼物--一个网格.网格有HH行WW列.每个单元格都是黑色或白色.所有黑色单元格都是四联通的,也就是说,只做水平或垂直移动且只经过 ...
- [AGC003F] Fraction of Fractal(矩阵乘法)
Description Snuke从他的母亲那里得到了生日礼物--一个网格.网格有H行W列.每个单元格都是黑色或白色.所有黑色单元格都是四联通的,也就是说,只做水平或垂直移动且只经过黑色单元格即可从任 ...
- AtCoder Grand Contest 003 F - Fraction of Fractal
题目传送门:https://agc003.contest.atcoder.jp/tasks/agc003_f 题目大意: 给定一个\(H×W\)的黑白网格,保证黑格四连通且至少有一个黑格 定义分形如下 ...
- Atcoder Grand Contest 003 F - Fraction of Fractal(矩阵乘法)
Atcoder 题面传送门 & 洛谷题面传送门 Yet another AGC F,然鹅这次就没能自己想出来了-- 首先需注意到题目中有一个条件叫做"黑格子组成的连通块是四联通的&q ...
- 【AGC003F】Fraction of Fractal
Description 原题链接 Solution 神题. 定义一个上边界或下边界的格子为"上下接口",当且仅当上下边界该位置的格子都是黑色的. "左 ...
- 题解-AtCoder-agc003F Fraction of Fractal(非矩阵快速幂解法)
Problem AtCoder-agc003F 题意:给出\(n\)行\(m\)列的01矩阵,一开始所有 \(1\) 连通,称此为\(1\)级分形,定义\(i\)级分形为\(i-1\)级分形中每个标示 ...
- AtCoder Grand Contest 003
AtCoder Grand Contest 003 A - Wanna go back home 翻译 告诉你一个人每天向哪个方向走,你可以自定义他每天走的距离,问它能否在最后一天结束之后回到起点. ...
- Atcoder/Topcoder 口胡记录
Atcoder/Topcoder 理论 AC Atcoder的❌游戏示范 兴致勃勃地打开一场 AGC 看 A 题,先 WA 一发,然后花了一年时间 Fix. 看 B 题,啥玩意?这能求? 睡觉觉. e ...
随机推荐
- MySQL slave状态之Seconds_Behind_Master zz
在MySQL的主从环境中,我们可以通过在slave上执行show slave status来查看slave的一些状态信息,其中有一个比较重要的参数Seconds_Behind_Master.那么你是否 ...
- 你真的了解负载均衡中间件nginx吗?
前言 nginx可所谓是如今最好用的软件级别的负载均衡了.通过nginx的高性能,并发能力强,占用内存下的特点,可以搭建高性能的代理服务.同时nginx还能作为web服务器,反向代理,动静分离服务器. ...
- 在IDEA中使用Spring写一个HelloWorld
准备工作 1.使用IDEA2018专业版, 我试了IDEA2019教育版和IDEA2020社区版,都无法顺利创建一个Spring项目,实在是恼火,一气之下,统统卸载掉. 重装了一个IDEA2018专业 ...
- adb常用命令食用方法
一.什么是adb? adb是Android Debug Bridge的缩写,即安卓调试桥:那什么是安卓调试桥?简单来说,就是一个通用命令行工具,允许计算机与模拟器或连接的安卓设备之间进行通信,提供各种 ...
- 量子纠错码——Clifford group
Clifford code Clifford group是什么? 简单的公式来表达,就是 \(Cl_{n}=\left\{U: U P_{n} U^{\dagger} \in P_{n}\right\ ...
- vue脚手架3.0的安装与使用
一.安装 1.先检查是否有安装vue (vue-cli3需要node大于等于8.9版本) //vue -V 2.如果没安装跳过.安装有3.0以下的版本就的先卸载掉以前的版本 npm uninstal ...
- Element-UI自定义主题
Element-UI自定义主题 1.介绍:我们可以自定义样式去覆盖element-ui的默认样式 // 在项目目录中新建 element-variables.scss 文件 // 上面为修改的变量 $ ...
- MySQL死锁系列-常见加锁场景分析
在上一篇文章<锁的类型以及加锁原理>主要总结了 MySQL 锁的类型和模式以及基本的加锁原理,今天我们就从原理走向实战,分析常见 SQL 语句的加锁场景.了解了这几种场景,相信小伙伴们也能 ...
- debug PHP程序(xdebug、IntelliJ IDEA)
之前写PHP程序的都是echo调试,今天感觉太麻烦了就想起研究一下IntelliJ IDEA如何调试PHP程序. 从网上查找了很多资料,大部分都提到在IDE里开启服务,一下就懵了,怎么启这么多服务呢. ...
- 「MoreThanJava」计算机系统概述
「MoreThanJava」 宣扬的是 「学习,不止 CODE」,本系列 Java 基础教程是自己在结合各方面的知识之后,对 Java 基础的一个总回顾,旨在 「帮助新朋友快速高质量的学习」. 当然 ...