zoukankan      html  css  js  c++  java
  • @atcoder


    @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
    ", 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
    ", 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
    ", add(x, y));
    */
    	}
    }
    

    @details@

    感觉分形题真有意思。

  • 相关阅读:
    UILabel 自适应大小
    CGAffineTransformScale
    CAKeyframeAnimation
    CABasicAnimation
    IOS 动画
    xcode 怎么样在发布release版本的时候 不输出log
    [转贴] C++ 判断主机是否处于联网状态下
    [转贴] 从零开始学C++之异常(二):程序错误、异常(语法、抛出、捕获、传播)、栈展开
    [转贴]从零开始学C++之异常(一):C语言错误处理方法、C++异常处理方法(throw, try, catch)简介
    [转贴]gsoap使用心得!
  • 原文地址:https://www.cnblogs.com/Tiw-Air-OAO/p/12410601.html
Copyright © 2011-2022 走看看