【矩阵加速】AGC003 Fraction of Fractal

分析:

想了半天才看见给的图是联通的。。。。

那就很简单了,设ud表示:上界和下界相同位置都为’#‘的数量。lr表示:左界和右界相同的位置都为‘#’的数量。
v v v表示’#‘的数量, e v ev ev表示左右相邻都是’#‘的数量, e h eh eh表示上下相邻都是’#'的数量。

显然,如果 l r > 0 且 u d > 0 lr>0且ud>0 lr>0ud>0,那无论怎么扩展,都一定联通,答案为1。
如果 l r = 0 且 u d = 0 lr=0且ud=0 lr=0ud=0,那么无论怎么扩展,扩展后一定都不联通,答案就是 v k − 1 v^{k-1} vk1
考虑 l r , u d lr,ud lrud有一个为0的情况。显然,哪个是0哪个不是并不重要。因为可以翻转这个图,使得 l r , u d lr,ud lr,ud交换(记得同时要交换eh,ev)

现在只讨论ud=0的情况。

显然,这种情况下,如果把每个1次扩展图看作一个点,连起来的图一定没有环(因为边都是上下方向的)。

那么联通块数量=点数量 ( V ) (V) (V)-边数量 ( E ) (E) (E)

那么有个很显然的递推式:
V k = V k − 1 ∗ v V_k=V_{k-1}*v Vk=Vk1v
E k = l r ∗ E k − 1 + e v ∗ V k − 1 E_k=lr*E_{k-1}+ev*V_{k-1} Ek=lrEk1+evVk1
上面那个很显然,就不解释了。
下面那个可以分为两部分,前半部分求的是两个图之间的边,后半部分是一个图内部的边。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 1010
#define MOD 1000000007
using namespace std;
typedef long long ll;
char s[MAXN][MAXN];
int n,m,v,lr,ud,ev,eh;
ll k;
struct node{
	ll x[3][3];
	node operator *=(const node&t) {
		int c[3][3]={0};
		for(int i=1;i<=2;i++)
			for(int j=1;j<=2;j++)
				for(int l=1;l<=2;l++)
					c[i][j]+=(x[i][l]*t.x[l][j])%MOD;
		for(int i=1;i<=2;i++)
			for(int j=1;j<=2;j++)
				x[i][j]=c[i][j]%MOD;
	}
}e,a;
ll fsp(ll x,ll y){
	ll res=1;
	while(y){
		if(y&1ll)
			res=res*x%MOD;
		x=x*x%MOD;
		y>>=1ll;	
	}
	return res;
}
int main(){
	SF("%d%d%lld",&n,&m,&k);
	for(int i=1;i<=n;i++)
		SF("%s",s[i]+1);
	for(int i=1;i<=m;i++)
		if(s[1][i]=='#'&&s[n][i]=='#')
			ud++;
	for(int i=1;i<=n;i++)
		if(s[i][1]=='#'&&s[i][m]=='#')
			lr++;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++){
			if(s[i][j]=='#'){
				v++;
				if(s[i-1][j]=='#')
					ev++;
				if(s[i][j-1]=='#')
					eh++;	
			}
		}
	if(ud!=0&&lr!=0){
		PF("1");
		return 0;
	}
	if(ud==0&&lr==0){
		PF("%lld",fsp(v,k-1ll));	
		return 0;
	}
	if(ud==0){
		ud=lr;
		ev=eh;
	}
	e.x[1][1]=ud;
	e.x[2][1]=ev;
	e.x[1][2]=0;
	e.x[2][2]=v;
	a.x[1][2]=1;
	if(k==0){
		PF("1\n");
		return 0;	
	}
	k--;
	while(k){
		if(k&1ll)
			a*=e;
		e*=e;
		k>>=1ll;
	}
	PF("%lld",(a.x[1][2]-a.x[1][1]+MOD)%MOD);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值