week14-矩阵快速幂

目录

 

D-Q老师染砖

题目:

Input:

Output:

Sample Input:

Sample Output:

题目分析:

代码:

E-Q老师度假

题目:

Input

Output

Sample Input

Sample Output

题目分析:

 

代码:


D-Q老师染砖

题目:

衣食无忧的 Q老师 有一天突发奇想,想要去感受一下劳动人民的艰苦生活。

具体工作是这样的,有 N 块砖排成一排染色,每一块砖需要涂上红、蓝、绿、黄这 4 种颜色中的其中 1 种。且当这 N 块砖中红色和绿色的块数均为偶数时,染色效果最佳。

为了使工作效率更高,Q老师 想要知道一共有多少种方案可以使染色效果最佳,你能帮帮他吗?

Input:

第一行为 T,代表数据组数。(1 ≤ T ≤ 100)

接下来 T 行每行包括一个数字 N,代表有 N 块砖。(1 ≤ N ≤ 1e9)

Output:

输出满足条件的方案数,答案模 10007。

Sample Input:

2
1
2

Sample Output:

2
6

题目分析:

  • 根据题意,因为是连续格子染色,很明显有子结构的性质,可以考虑 DP 。但是 n 很大,因此考虑矩阵快速幂优化 DP。
  • 题目问 n 个格子,红绿均为偶数的染色方案数 ,因此令 A[i] 表示 i 个格子,红绿均为偶数的染色方案数 ,但是只有A[I]不能表示所有的状态,而偶数需要从奇数转移而来,所以添加 B[i] 表示 i 个格子,红绿均为奇数的染色方案数 ,C[i] 表示 i 个格子,红绿有一个为偶数的染色方案数。
  • 其A,B,C之间的线性递推公式及由递推式导出的矩阵快速幂等式如下:

代码:

#include<iostream>
#include<stdio.h> 
#include<string.h> 
using namespace std;

//a[i]表示i个格子 ,红绿均为偶数 
//b[i]表示i个格子 ,红绿均为奇数 
//c[i]表示i个格子 ,红绿有一个偶数 

const int n=3;
const int p=10007;

struct Matrix
{
	int x[n][n];
	Matrix operator*(const Matrix& t) const
	{
		Matrix re;
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<n;j++)
			{
				re.x[i][j]=0;
				for(int k=0;k<n;k++)
				{
					re.x[i][j]+=x[i][k]*t.x[k][j]%p;
					re.x[i][j]%=p;
				}
			}
		}
		return re;
	}
	Matrix(){memset(x,0,sizeof(x));}
	Matrix(const Matrix &t){memcpy(x,t.x,sizeof(x));}
};
Matrix quick_pow(Matrix a,int x)
{
	Matrix re;
	for(int i=0;i<n;i++)
	{
		re.x[i][i]=1;
	} 
	while(x)
	{
		if(x&1)	re=re*a;
		a=a*a;
		x>>=1; 
	}
	return re;
}
int main()
{
	int t;
	cin>>t;
	int N;
	int ans;
	while(t--)
	{
		cin>>N;
		ans=0;
		Matrix a;
		a.x[0][0]=2;a.x[0][1]=0;a.x[0][2]=1;
		a.x[1][0]=0;a.x[1][1]=2;a.x[1][2]=1;
		a.x[2][0]=2;a.x[2][1]=2;a.x[2][2]=2;
		a=quick_pow(a,N-1);
		ans+=(2*a.x[0][0] +0*a.x[0][1]+2*a.x[0][2])%p;
		cout<<ans<<endl;
	} 
	return 0;
}

E-Q老师度假

题目:

忙碌了一个学期的 Q老师 决定奖励自己 N 天假期。

假期中不同的穿衣方式会有不同的快乐值。

已知 Q老师 一共有 M 件衬衫,且如果昨天穿的是衬衫 A,今天穿的是衬衫 B,则 Q老师今天可以获得 f[A][B] 快乐值。

在 N 天假期结束后,Q老师最多可以获得多少快乐值?

Input

输入文件包含多组测试样例,每组测试样例格式描述如下:

第一行给出两个整数 N M,分别代表假期长度与 Q老师的衬衫总数。(2 ≤ N ≤ 100000, 1 ≤ M ≤ 100)

接下来 M 行,每行给出 M 个整数,其中第 i 行的第 j 个整数,表示 f[i][j]。(1 ≤ f[i][j] ≤ 1000000)

测试样例组数不会超过 10。

Output

每组测试样例输出一行,表示 Q老师可以获得的最大快乐值。

Sample Input

3 2
0 1
1 0
4 3
1 2 3
1 2 3
1 2 3

Sample Output

2
9

题目分析:

  • 根据题意,因为天数连续,很明显有子结构的性质,可以考虑 DP。
  • 题目问 n 天后最多快乐值,且每天的快乐值由今日与昨日两天的衣服决定 ,因此令𝑓[i][𝑗]表示第 i 天,穿的衣服为 j 所获得的快乐 值总和。DP 转移方程为:枚举前一天穿的衣服为 k,则   𝑓[𝑖][𝑗]=max(𝑓[𝑖−1][𝑘]+𝐻[𝑘][𝑗]) ,1≤𝑘≤𝑀。
  • 但又因为直接求解的复杂度为:𝑂(𝑁∗𝑀∗𝑀)=𝑂(e9),不可行。所以考虑矩阵快速幂优化。
  • 其根据DP转移方程式导出的矩阵快速幂等式如下:

 

 

与一般的矩阵快速幂的转变与区别如下:

(另 注意数据范围,此处数据范围应为long long)

代码:

#include<iostream>
#include<stdio.h> 
#include<string.h> 
#include<algorithm>
using namespace std;
const int maxn=1e5+5;
const int maxm=1e2+5;
long long int f[maxm][maxm];//f[i][j]表示第i天,穿的衣服为j所获得的快乐值总和

int N,M;

struct Matrix
{
	long long int x[maxm][maxm];
	Matrix operator*(const Matrix& t) const
	{
		Matrix re;
		for(int i=0;i<M;i++)
		{
			for(int j=0;j<M;j++)
			{
				re.x[i][j]=0;
				for(int k=0;k<M;k++)
				{
					re.x[i][j]=max(re.x[i][j],x[i][k]+t.x[k][j]);
				}
			}
		}
		return re;
	}
	Matrix(){memset(x,0,sizeof(x));}
	Matrix(const Matrix &t){memcpy(x,t.x,sizeof(x));}
};
Matrix quick_pow(Matrix a,int x)
{
	Matrix re;
	int n=M;
	for(int i=0;i<M;i++)
	{
		re.x[i][i]=0;
	} 
	while(x)
	{
		if(x&1)	re=re*a;
		a=a*a;
		x>>=1; 
	}
	return re;
}
int main()
{
	long long int ans;
	while(cin>>N>>M)
	{
		Matrix a;
		ans=0;
		for(int i=0;i<M;i++)
		{
			for(int j=0;j<M;j++)
			{
				cin>>f[i][j];
			}
		}
		for(int i=0;i<M;i++)
		{
			for(int j=0;j<M;j++)
			{
				a.x[i][j]=f[j][i];
			}
		}
		a=quick_pow(a,N-1);
		for(int i=0;i<M;i++)
		{
			for(int j=0;j<M;j++)
			{
				ans=max(ans,a.x[i][j]);
			}
		}
		cout<<ans<<endl;	
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值