地斗主(矩阵快速幂)

链接:https://ac.nowcoder.com/acm/contest/213/A
来源:牛客网
 

题目描述

一场考试怎么能没有大模拟呢qwq,SKY_magician听说过猪国杀、德州扑克、UNO、杀蚂蚁等等,但是他觉得这些模拟写起来太短了,于是他就设计了一个肯定不会超过1500行的大模拟(划掉)。

现在你有一个4*n的棋盘和一坨地斗主骨牌,这些骨牌都是1*2的。请你求出用骨牌完全覆盖这个棋盘的方案数对m取模的值。

输入描述:

第一行一个T表示数据组数

对于每组数据输入n和m,n和m意义见题目描述。

输出描述:

输出答案

示例1

输入

复制

3
1 10000
3 10000
5 10000

输出

复制

1
11
95

备注:

对于10%的数据 1<=n<=6
对于50%的数据 1<=n<=10000
对于70%的数据 1<=n<=5e7
对于100%的数据 1<=n<=1e9,1<=m<=1e5,T<=1500

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
#include<set>
#include<vector>
#include<map>
#include<cmath>
const int maxn=1e5+5;
typedef long long ll;
using namespace std;

ll MOD;
struct mat
{
  ll a[5][5];
};
mat  Mul(mat a,mat b)
{
	mat ans;
	memset(ans.a,0,sizeof(ans.a));
	for(int t=1;t<=4;t++)
	{
		for(int j=1;j<=4;j++)
		{
			for(int k=1;k<=4;k++)
			{
				ans.a[t][j]=(ans.a[t][j]+a.a[t][k]*b.a[k][j])%MOD;
			}
		}
	}
	return ans;
 
}
mat ans;
ll quickpow(ll n)
{
   mat res;
   memset(res.a,0,sizeof(res.a));
   res.a[1][1]=1;
   res.a[1][2]=5;
   res.a[1][3]=1;
   res.a[1][4]=-1;
   res.a[2][1]=1;
   res.a[3][2]=1;
   res.a[4][3]=1;
   while(n)
   {
   	if(n&1)
   	{
   		ans=Mul(res,ans);
	}
	res=Mul(res,res);
	n>>=1;
   }
   return ans.a[1][1];
}
int main()
{
	ll n;
    int T;
    cin>>T;
	while(T--)
	{
		scanf("%lld%lld",&n,&MOD);
		memset(ans.a,0,sizeof(ans.a));
	    ans.a[1][1]=36;
	    ans.a[2][1]=11;
	    ans.a[3][1]=5;
	    ans.a[4][1]=1;
	    if(n==1)
	    {
	    	printf("1\n");
		}
		else if(n==2)
	    {
	    	printf("5\n");
		}
		else if(n==3)
		{
			printf("11\n");
		}
		else if(n==4)
		{
			printf("36\n");
		}
		else 
		{
			ll s=quickpow(n-4)+MOD;
			printf("%lld\n",(s)%MOD);
		}
		
	}
 
   return 0;
}

猜你喜欢

转载自blog.csdn.net/lbperfect123/article/details/89502097