矩陣快速冪(14)

矩陣快速冪

先說明一下:看到矩陣快速冪,我先想到的是快速冪,後來感覺差不多。
不會快速冪的可以先看一下這篇:快速冪
廢話不多說,直接上板子:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=10000;  //先不用管這個,一做題就明白了
int f=2;
struct node
{
	ll materix[5][5];
};

node mul(node a,node b)  //矩陣乘法 
{
	node res;
	memset(res.materix,0,sizeof res.materix);
	for(int i=1;i<=f;i++)
		for(int j=1;j<=f;j++)
			for(int k=1;k<=f;k++)
				res.materix[i][j]=(res.materix[i][j]+a.materix[i][k]*b.materix[k][j])%mod;
	return res;	
}

node ksm(node a,ll b)    //快速冪
{
	node ans;
	memset(ans.materix,0,sizeof ans.materix);
	for(int i=1;i<=f;i++)
		ans.materix[i][i]=1;
	while(b)
	{
		if(b&1)
			ans=mul(ans,a);
		b>>=1;
		a=mul(a,a);
	}
	return ans;
}

大體就是上面那套板子,按照小編目前短淺的理解,矩陣快速冪的難度在於找到最初始的矩陣和乘的矩陣…
來幾個板子題:

傳送門:Fibonacci POJ - 3070

很明顯直接算不現實,這時候就得用到矩陣快速冪,這裏就是那個mod的作用

//#include<bits/stdc++.h>
#include <iostream>
#include<cstring>
#include<stdio.h>
using namespace std;
typedef long long ll;
const int mod=10000;
int f=2;
struct node
{
	ll materix[5][5];
};

node mul(node a,node b)  //矩陣乘法 
{
	node res;
	memset(res.materix,0,sizeof res.materix);
	for(int i=1;i<=f;i++)
		for(int j=1;j<=f;j++)
			for(int k=1;k<=f;k++)
				res.materix[i][j]=(res.materix[i][j]+a.materix[i][k]*b.materix[k][j])%mod;
	return res;	
}

node ksm(node a,ll b)
{
	node ans;
	memset(ans.materix,0,sizeof ans.materix);
	for(int i=1;i<=f;i++)
		ans.materix[i][i]=1;
	while(b)
	{
		if(b&1)
			ans=mul(ans,a);
		b>>=1;
		a=mul(a,a);
	}
	return ans;
}

int main()
{
	ll N;
	while(cin>>N&&N!=-1)
	{
		if(N==1||N==2)
			printf("1\n");
		else if(N==0)
			printf("0\n");
		else
		{
			node a,b;
			a.materix[1][1]=1; a.materix[1][2]=1;
			a.materix[2][1]=1; a.materix[2][2]=0;   //a是那個冪矩陣,
			b.materix[1][1]=1; b.materix[1][2]=0;
			b.materix[2][1]=1; b.materix[2][2]=0;   //b是最初始的矩陣
	        //假如a*a*a*b就是a^3*b,所以先求用快速冪求a的三次方,再用結果和b相乘
	        //注意乘的順序,矩陣相乘a*b!=b*a,順序不能搞錯
	        //這裏個人有個小訣竅,因爲.f(n)=a*f(n-1)+b*f(n-2)+c,所以前邊的那個應該是構造矩陣
			node ans = ksm(a ,N-2);  //從3開始,所以-2
			ans = mul(ans ,b) ;
			printf("%d\n",ans.materix[1][1] ) ;
		}
	}
	return 0;
}

傳送門: Tr A HDU - 1575

一模一樣的板子題

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,k;
int mod=9973;
struct node
{
	ll materix[11][11];
};
node mul(node a,node b)  //矩陣乘法 
{
	node res;
	memset(res.materix,0,sizeof res.materix);
	for(int i=0;i<n;i++)
		for(int j=0;j<n;j++)
			for(int k=0;k<n;k++)
				res.materix[i][j]=(res.materix[i][j]+a.materix[i][k]*b.materix[k][j])%mod;
	return res;	
}  
node ksm(node a,ll b)
{
	
	node ans;
	memset(ans.materix,0,sizeof ans.materix);
	for(int i=0;i<n;i++)
		ans.materix[i][i]=1;
	while(b)
	{
		if(b&1)
			ans=mul(ans,a);
		b>>=1;
		a=mul(a,a);
	}
	return ans;
}
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		cin>>n>>k;
		node c;
		for(int i=0;i<n;i++)
			for(int j=0;j<n;j++)
				cin>>c.materix[i][j];

		node ans=ksm(c,k);
		int sum=0;
		for(int i=0;i<n;i++)
			sum=sum+ans.materix[i][i]%mod;
		printf("%d\n",sum%mod);
	}
	return 0;
}

傳送門: A Simple Math Problem HDU - 1757

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll k,m;
int aa[15];
struct node
{
	ll materix[15][15];
};
node mul(node a,node b)  //矩陣乘法 
{
	node res;
	memset(res.materix,0,sizeof res.materix);
	for(int i=1;i<=10;i++)
		for(int j=1;j<=10;j++)
			for(int k=1;k<=10;k++)
				res.materix[i][j]=(res.materix[i][j]+a.materix[i][k]*b.materix[k][j])%m;
	return res;	
}  
node ksm(node a,ll b)
{
	node ans;
	memset(ans.materix,0,sizeof ans.materix);
	for(int i=1;i<=10;i++)
		ans.materix[i][i]=1;
	while(b)
	{
		if(b&1)
			ans=mul(ans,a);
		b>>=1;
		a=mul(a,a);
	}
	return ans;
}

int main()
{
	while(~scanf("%lld %lld",&k,&m))
	{
		if(k<10)
		{
			cout<<k%m<<endl;
			continue;
		}
		else
		{
			node a,b;
			for(int i=0;i<=15;i++)
				for(int j=0;j<=15;j++)
					a.materix[i][j]=b.materix[i][j]=0;
				
			for(int i=1;i<=10;i++)
				cin>>a.materix[1][i];
			for(int i=1;i<=9;i++)
				a.materix[i+1][i]=1;

			for(int i=1;i<=10;i++)
				b.materix[i][1]=10-i;
	
			node ans=ksm(a,k-9);
			ans=mul(ans,b);
			printf("%d\n",ans.materix[1][1]%m);
		}
	}
	return 0;
}

傳送門: Recursive sequence HDU - 5950(矩陣的構造)

這應該是一個簡單的矩陣構造,希望讀者能認認真真的學會如何構造一個矩陣。
這個題的構造難在構造矩陣當時構造出來後就懶得寫板子了,所以直接CV代碼。
關於這個題,讀者應該去百度如何構造矩陣,去學習多種矩陣的構造方法以防萬一。

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

#define ll long long
const ll maxn = 7;
const ll mod = 2147493647;

struct mat
{
    ll m[maxn][maxn];
};

mat operator *(mat x, mat y)
{
    mat ret;
    for(int i = 0; i < maxn; i++)
    {
        for(int j = 0; j < maxn; j++)
        {
            ret.m[i][j] = 0;
            for(int k = 0; k < maxn; k++)
            {
                ret.m[i][j] = (x.m[i][k] * y.m[k][j] + ret.m[i][j]) % mod;
            }
        }
    }
    return ret;
}

mat pow_mat(mat a, ll fuck)
{
    mat ret;
    memset(ret.m,0,sizeof(ret.m));
    for(int i = 0; i < maxn; i++) ret.m[i][i] = 1;
    while(fuck)
    {
        if(fuck&1) ret = ret*a;
        a = a*a;
        fuck >>= 1;
    }
    return ret;
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        ll f1, f2, m;
        scanf("%lld%lld%lld",&m,&f1,&f2);
        if(m == 1) printf("%lld\n",f1);
        else if(m == 2) printf("%lld\n",f2);
        else
        {
            mat a;
            memset(a.m,0,sizeof(a.m));
            a.m[0][0] = f2;
            a.m[1][0] = f1;
            a.m[2][0] = 1;
            a.m[3][0] = 2;
            a.m[4][0] = 4;
            a.m[5][0] = 8;
            a.m[6][0] = 16;
            mat b =
            {
                1, 2, 1, 4, 6, 4, 1,
                1, 0, 0, 0, 0, 0, 0,
                0, 0, 1, 0, 0, 0, 0,
                0, 0, 1, 1, 0, 0, 0,
                0, 0, 1, 2, 1, 0, 0,
                0, 0, 1, 3, 3, 1, 0,
                0, 0, 1, 4, 6, 4, 1
            };
            a = pow_mat(b,m-2)*a;
            printf("%lld\n",a.m[0][0]);
        }
    }
    return 0;
}

還有三個水題…讀者可以用來練手

傳送門:1126 求遞推序列的第N項

傳送門:1113 矩陣快速冪

傳送門:1137 矩陣乘法

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章