矩阵专题(续)

哈哈哈,失踪人员回归。最近总是在忙一些乱七八糟的事情,终于有了一段空闲时间可以刷刷题了。学姐给我准备了kuangbin先生的矩阵专题,作为我的矩阵终结专题。(初学者请先看我的矩阵专题前三篇)


第一题 CodeForces 450B

分析:这道题看似是一道矩阵题,但是实际上是一道模拟题。看题目给出的公式 f(i)=f(i-1)+f(i+1),i>=2,那么转换一下得到了f(i)=f(i-1)-f(i-2),i>=3,当然这题可以使用矩阵快速幂来算,但是多此一举。不妨将f(1)=x  f(2)=y代进去计算前几项,那么依次得到 x   y   y-x   -x   -y   x-y   x   y   ......,我们发现这个数列是有循环节的,而且必定为6,那么只需要计算前六个,n取一下模即可得到答案。注意:x  y可能是负数,但是答案一定得是非负整数。

#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
#pragma comment(linker, "/STACK:1024000000,1024000000")

using namespace std;
#define   maxn          200000+10
#define   lson          l,m,rt<<1
#define   rson          m+1,r,rt<<1|1
#define   clr(x,y)      memset(x,y,sizeof(x))
#define   rep(i,n)      for(int i=0;i<(n);i++)
#define   repf(i,a,b)   for(int i=(a);i<=(b);i++)
#define   pii           pair<int,int>
#define   mp            make_pair
#define   FI            first
#define   SE            second
#define   IT            iterator
#define   PB            push_back
#define   Times         10

typedef   long long     ll;
typedef   unsigned long long ull;
typedef   long double   ld;

const double eps = 1e-10;
const double  pi = acos(-1.0);
const  ll    mod = 1e9+7;
const  int   inf = 0x3f3f3f3f;

inline void RI(int& x)
{
    x=0;
    char c=getchar();
    while(!((c>='0'&&c<='9')||c=='-'))c=getchar();
    bool flag=1;
    if(c=='-')
    {
        flag=0;
        c=getchar();
    }
    while(c<='9'&&c>='0')
    {
        x=x*10+c-'0';
        c=getchar();
    }
    if(!flag)x=-x;
}

//--------------------------------------------------

ll dat[10];
int main(){
	//freopen("d:\\acm\\in.in","r",stdin);
	ll n;
	scanf("%I64d %I64d",&dat[1],&dat[2]);
	dat[1]=(dat[1]+mod)%mod;
	dat[2]=(dat[2]+mod)%mod;
	scanf("%I64d",&n);
	dat[0]=(dat[1]-dat[2]+mod)%mod;
	for(int i=3;i<6;i++)
		dat[i]=(dat[i-1]-dat[i-2]+mod)%mod;
	printf("%I64d\n",dat[n%6]);
    return 0;
}



第二题  HDU 5015

题目大意:给你一个矩阵,矩阵第一行中,第一个数为空,之后的数就是233,2333,23333。。。一直轮下去。然后,矩阵第一列上,第一个数为空(即第一行第一列的那个数为空),之后的所有数会给出。接着,告诉你这个矩阵其他元素都是按照maze[i][j]=maze[i-1][j]+maze[i][j-1]的规律来计算的,让你求出矩阵右下角的数是多少。

分析:一开始没有往矩阵方面想,前段时间数论做多了之后很容易就发现最后的maze[n][m]的数可以通过已知的数乘一个数(满足一个组合数,杨辉三角),然后相加得到。虽然我公式推出来了,但是复杂度太高,而且写起来还麻烦,就被我pass了,有兴趣的朋友可以自己推一推写一写。然后回过去想矩阵做法的话,立刻就想到了(提示n的值很大,但是m的值不大)。将输入的23(第一个23是补充上去的,为了和之后的23333对齐),maze[1][0],maze[2][0],maze[3][0],......作为初始值,根据公式很容易看出转换的矩阵,除了第一个233是前一个23乘10加3,其他的都是maze[i][j]=maze[i-1][j]+maze[i][j-1]。


#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
#pragma comment(linker, "/STACK:1024000000,1024000000")

using namespace std;
#define   maxn          10+10
#define   lson          l,m,rt<<1
#define   rson          m+1,r,rt<<1|1
#define   clr(x,y)      memset(x,y,sizeof(x))
#define   rep(i,n)      for(int i=0;i<(n);i++)
#define   repf(i,a,b)   for(int i=(a);i<=(b);i++)
#define   pii           pair<int,int>
#define   mp            make_pair
#define   FI            first
#define   SE            second
#define   IT            iterator
#define   PB            push_back
#define   Times         10

typedef   long long     ll;
typedef   unsigned long long ull;
typedef   long double   ld;

const double eps = 1e-10;
const double  pi = acos(-1.0);
const  ll    mod = 1e9+7;
const  int   inf = 0x3f3f3f3f;

inline void RI(int& x)
{
    x=0;
    char c=getchar();
    while(!((c>='0'&&c<='9')||c=='-'))c=getchar();
    bool flag=1;
    if(c=='-')
    {
        flag=0;
        c=getchar();
    }
    while(c<='9'&&c>='0')
    {
        x=x*10+c-'0';
        c=getchar();
    }
    if(!flag)x=-x;
}

//--------------------------------------------------

ll mul(ll a,ll b){
	ll ans=0;
	while(b){
		if(b&1)ans=(ans+a)%mod;
		a=(a+a)%mod;
		b>>=1;
	}
	return ans;
}
struct matrix{
	int n;
	ll maze[maxn][maxn];
	void init(int n){
		this->n=n;
		clr(maze,0);
	}
	matrix operator * (const matrix& rhs){
		matrix ans;
		ans.init(n);
		for(int i=0;i<n;i++)
			for(int j=0;j<n;j++)
				for(int k=0;k<n;k++)
					ans.maze[i][j]=(ans.maze[i][j]+maze[i][k]*rhs.maze[k][j])%10000007;
		return ans;
	}
};
matrix qlow(matrix a,int n){
	matrix ans;
	ans.init(a.n);
	for(int i=0;i<a.n;i++)ans.maze[i][i]=1;
	while(n){
		if(n&1)ans=ans*a;
		a=a*a;
		n>>=1;
	}
	return ans;
}
int main(){
	//freopen("d:\\acm\\in.in","r",stdin);
	int n,m;
	while(~scanf("%d %d",&n,&m)){
		matrix ans;
		ans.init(n+2);
		for(int i=1;i<=n;i++)
			scanf("%lld",&ans.maze[0][i]);
		ans.maze[0][0]=23;
		ans.maze[0][n+1]=1;
		matrix ant;
		ant.init(n+2);
		for(int i=0;i<=n;i++)
			ant.maze[0][i]=10,ant.maze[n+1][i]=3;
		ant.maze[n+1][n+1]=1;
		for(int i=1;i<=n;i++)
			for(int j=i;j<=n;j++)
				ant.maze[i][j]=1;
		ant=qlow(ant,m);
		ans=ans*ant;
		printf("%lld\n",ans.maze[0][n]);
	}
    return 0;
}




第三题 HDU 4990
分析:简单来看就是一个数列计算问题。F(0)=0.如果i为奇数,那么F(i)=2*F(i-1)+1;如果i为偶数,那么F(i)=2*F(i-1)。很显然是一道矩阵问题,我们不妨将两步合成一步来做F(i)=4*F(i-2)+2,i为偶数,那么我们按照2个2个来计算,计算到不超过n的最大偶数。最后,如果n为奇数的话,再计算一步即可。


#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
#pragma comment(linker, "/STACK:1024000000,1024000000")

using namespace std;
#define   maxn         	0+10
#define   lson          l,m,rt<<1
#define   rson          m+1,r,rt<<1|1
#define   clr(x,y)      memset(x,y,sizeof(x))
#define   rep(i,n)      for(int i=0;i<(n);i++)
#define   repf(i,a,b)   for(int i=(a);i<=(b);i++)
#define   pii           pair<int,int>
#define   mp            make_pair
#define   FI            first
#define   SE            second
#define   IT            iterator
#define   PB            push_back
#define   Times         10

typedef   long long     ll;
typedef   unsigned long long ull;
typedef   long double   ld;

const double eps = 1e-10;
const double  pi = acos(-1.0);
const  ll    mod = 1e9+7;
const  int   inf = 0x3f3f3f3f;

inline void RI(int& x)
{
    x=0;
    char c=getchar();
    while(!((c>='0'&&c<='9')||c=='-'))c=getchar();
    bool flag=1;
    if(c=='-')
    {
        flag=0;
        c=getchar();
    }
    while(c<='9'&&c>='0')
    {
        x=x*10+c-'0';
        c=getchar();
    }
    if(!flag)x=-x;
}

//--------------------------------------------------

int m;
struct matrix{
	int n;
	ll maze[maxn][maxn];
	void init(int n){
		this->n=n;
		clr(maze,0);
	}
	matrix operator * (const matrix& rhs){
		matrix ans;
		ans.init(n);
		for(int i=0;i<n;i++)
			for(int j=0;j<n;j++)
				for(int k=0;k<n;k++)
					ans.maze[i][j]=(ans.maze[i][j]+maze[i][k]*rhs.maze[k][j])%m;
		return ans;
	}
};
matrix qlow(matrix a,ll n){
	matrix ans;
	ans.init(a.n);
	for(int i=0;i<a.n;i++)ans.maze[i][i]=1;
	while(n){
		if(n&1)ans=ans*a;
		a=a*a;
		n>>=1;
	}
	return ans;
}
int main(){
	//freopen("d:\\acm\\in.in","r",stdin);
	int n;
	while(~scanf("%d %d",&n,&m)){
		matrix ant;
		ant.init(2);
		ant.maze[0][0]=4;
		ant.maze[1][0]=2;
		ant.maze[1][1]=1;
		ant=qlow(ant,n/2);
		ll ans=ant.maze[1][0];
		if(n&1)ans=(ans*2+1)%m;
		cout<<ans<<endl;
	}
    return 0;
}




第四题 UVA 11651
分析:不会做,看了别人的题解才会的。这里我讲一下思路,作为纯DP题的话,转移方程很好想,但是score太大,无法记忆化搜索;但是作为纯矩阵题的话,一开始完全想不到如何构造矩阵。然后把两者合在一起想,就发现还是矩阵的套路,但是要加上DP的思想(以DP的状态为转移)。将一开始所有可能转移的数据全部算出来作为初始数据,部分数据直接移位就行了,主要就是最后一行的数据(要计算的新数据),需要用到前面所有数据来计算。

我知道读者肯定没有看懂,无妨,请转到这位大神的博客,他写得很好,这里我贴下我的代码

http://www.cnblogs.com/AOQNRMGYXLMV/p/5256508.html

#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值