Light1052 String Growth【矩阵快速幂】

题意:一个字符串由a,b组成,字符串转化为下一个的规则为:a->b,b->ab,告诉你,第n个、第m个字符串的长度,算第k个的长度


思路:这个变化规则,我们可以发现长度的变化是斐波拉契数列,我们设第1项有q个a,p个b,往下推,q、p前面的系数也是斐波拉契数列,我们快速幂算第n、m项q、p的前的系数,a1*q+b1*p = 第n项的长度,解二元一次方程,算出q、p算第k项


解方程:ax + by = m;cx + dy = n

有无实数解:yu1 = (md-bn) % (ad-bc);yu2 = (mc-an) % (bc-ad); 判断余数,余数都为0,有解

解:x = (md-bn) / (ad-bc);y = (mc-an)/(bc-ad)


#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<stdlib.h>
#include<math.h>
#include<vector>
#include<list>
#include<map>
#include<stack>
#include<queue>
#include<algorithm>
#include<numeric>
#include<functional>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int maxn = 5; 
typedef long long ll;
int MOD,N;
struct data
{
	ll s[maxn][maxn];
}res,tp;

void init()
{
	N = 2;
	memset(res.s,0,sizeof res.s);
	memset(tp.s,0,sizeof tp.s);
	res.s[1][1] = 1;res.s[2][2] = 1;
	tp.s[1][1] = 1;tp.s[1][2] = 1;
	tp.s[2][1] = 1;tp.s[2][2] = 0;
}

struct data mat(struct data &x,struct data &y)
{
	struct data temp;
	memset(temp.s,0,sizeof temp.s);
	for(int i = 1; i <= N; i++)
	{
		for(int j = 1; j <= N; j++)
		{
			for(int k = 1; k <= N; k++)
			{
				temp.s[i][j] = (temp.s[i][j] + x.s[i][k] * y.s[k][j]) % MOD;
			}
		}
	}
	return temp;
}

struct data mpow(struct data &a,ll b)
{
	while(b)
	{
		if(b&1) res = mat(res,a);
		b >>= 1;
		a = mat(a,a); 
	}
	return res;
}

int main(void)
{
	ll n,m,x,y,k,q1,q2,p1,p2,p,q;
	int kase = 1,T;
	MOD = 1e9+7;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%lld%lld%lld%lld%lld",&n,&x,&m,&y,&k);
		if(n > m) 
		{
			swap(n,m);
			swap(x,y);
		}
		q1 = q2 = p1 = p2 = 0;
		flag = 1;
		init();
		if(n == 1)
		{
			q1 = 1;
			p1 = 1;
		}
		else
		{
			res = mpow(tp,n-2);
			q1 = ( res.s[1][1] * 1 + res.s[1][2] * 1 ) % MOD;
			p1 = ( res.s[1][1] * 2 + res.s[1][2] * 1 ) % MOD;
		}
		
		init();
		if(m == 1)
		{
			q2 = 1;
			p2 = 1;
		}
		else
		{
			res = mpow(tp,m-2);
			q2 = ( res.s[1][1] * 1 + res.s[1][2] * 1 ) % MOD;
			p2 = ( res.s[1][1] * 2 + res.s[1][2] * 1 ) % MOD;
		}
		printf("Case %d: ",kase++);
		if( (x*p2-p1*y)%(q1*p2-p1*q2) || (x*q2-q1*y)%(p1*q2-q1*p2) )
			printf("Impossible\n");
		else
		{
			q = (x*p2-p1*y)/(q1*p2-p1*q2);
			p = (x*q2-q1*y)/(p1*q2-q1*p2);
			if(q < 0 || p < 0)
				printf("Impossible\n");
			else
			{
				init();
				ll ans;
				if(k == 1)
					ans = q+p;
				else
				{
					res = mpow(tp,k-2);
					ans = res.s[1][2] * (p+q)%MOD + res.s[1][1] * (2*p+q)%MOD;
				}
				ans %= MOD;
				printf("%lld\n",ans);
			}
		}
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值