首页 > 代码库 > PJOI 1024 Hamilton Circles 矩阵快速幂

PJOI 1024 Hamilton Circles 矩阵快速幂

题意:给定2*2*n的立方体

我们认为1*1*1 的小格子是一个顶点

有公共面的顶点认为有一条无向边

给定n

问有多少条哈密顿回路


结论:a[n] = 4*a[n-1] - a[n-2]; (n>=3)

别问我怎么知道的,我也不知道。。。TAT

然后有注意一点,这里面涉及到了减法,矩阵快速幂后要注意ans可能<0 ,加个mod即可。

#include"cstdio"
#include"iostream"
#include"queue"
#include"algorithm"
#include"set"
#include"queue"
#include"cmath"
#include"string.h"
#include"vector"
using namespace std;
#define ll long long
const ll mod = 1000000007;
ll n;
#define Matr 4 //矩阵大小,注意能小就小

struct mat//矩阵结构体,a表示内容,size大小 矩阵从1开始
{
    ll a[Matr][Matr],size;
    mat()
    {
        size=0;
        memset(a,0,sizeof(a));
    }
};
mat multi(mat m1,mat m2,ll mod)//两个相等矩阵的乘法,对于稀疏矩阵,有0处不用运算的优化 
{
    mat ans=mat();    ans.size=m1.size;
    for(ll i = 1; i <= ans.size; i++)
		for(ll j = 1; j <= ans.size; j++)
			for(ll k = 1; k <= ans.size; k++)
				ans.a[i][j] = (ans.a[i][j]+m1.a[i][k]*m2.a[k][j])%mod;
    return ans;
}
mat quickmulti(mat m,ll n,ll mod)//二分快速幂 
{
    mat ans=mat();
    for(ll i=1;i<=m.size;i++)ans.a[i][i]=1;
    ans.size=m.size;
    while(n)
    {
        if(n&1)ans=multi(m,ans,mod);
        m=multi(m,m,mod);
        n>>=1;
    }
    return ans;
}
/*
ans^=n ->
mat ans=mat();
ans.size=Size;
初始化ans矩阵
ans=quickmulti(ans,n,mod);
*/
int main(){
	ll T, Cas = 1;scanf("%lld",&T);
	while(T--){
		scanf("%lld",&n);
		printf("Case %lld: ",Cas++);
		if(n==1)puts("1");
		else if(n==2)puts("6");
		else if(n==3)puts("22");
		if(n<=3)continue;
		mat tmp=mat();
		tmp.size = 2;
		tmp.a[1][1] = 4;	tmp.a[1][2] = -1;
		tmp.a[2][1] = 1;	tmp.a[2][2] = 0;
		tmp = quickmulti(tmp, n-3, mod);
		ll ans = tmp.a[1][1]*22+tmp.a[1][2]*6;
		ans %= mod;
		while(ans<0)ans+=mod;
		printf("%lld\n",ans);
	}
	return 0;
}