NOIP 考后欢乐赛 T2 中国象棋

版权声明:虽然本蒟蒻很菜,但各位dalao转载请注明出处谢谢。 https://blog.csdn.net/xuxiayang/article/details/84675376

链接

https://www.luogu.org/problemnew/show/U54182


大意

在一个 n × n n\times n 的棋盘上放置只可以攻击左右格子的兵,问在每一行至少有两个兵且同一行的兵不相邻的方案数


思路

首先我们打表,然后发现就是斐波那契做两次前缀和,于是我们就可以用矩阵乘法瞎搞啦!
如图0..


代码

#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cctype>
using namespace std;typedef unsigned long long LL;
LL n,p;
inline char Getchar()
{
    static char buf[1000000],*p1=buf+1000000,*pend=buf+1000000;
    if(p1==pend)
	{
        p1=buf; pend=buf+fread(buf,1,1000000,stdin);
        if (pend==p1) return -1;
    }
    return *p1++;
}
inline LL read()
{
	char c;int d=1;LL f=0;
	while(c=Getchar(),!isdigit(c))if(c==45)d=-1;f=(f<<3)+(f<<1)+c-48;
	while(c=Getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
	return d*f;
}
inline void write(register LL x)
{
	if(x<0)write(45),x=-x;
	if(x>9)write(x/10);
	putchar(x%10+48);
	return;
}
struct node{long long a[4][4];}ans,x;
inline LL ksc(LL a,LL b,LL p)//快速乘
{
    a%=p;b%=p;
    long long c=(long double)a*b/p;
    long long ans=a*b-c*p;
    if(ans<0) ans+=p;
    else if(ans>=p) ans-=p;
    return ans;
}
inline node mul(node x,node y)//矩阵乘法
{
    node c;
    memset(&c,0,sizeof(c));
    for(register int k=0;k<4;k++)
     for(register int i=0;i<4;i++)
      for(register int j=0;j<4;j++)
    (c.a[i][j]+=ksc(x.a[i][k],y.a[k][j],p))%=p;
    return c;
}
inline void jzksm(LL y)//矩阵快速幂
{
	ans.a[0][1]=1;ans.a[0][2]=1;
	x.a[0][1]=x.a[0][2]=x.a[1][0]=1;
	x.a[1][1]=x.a[1][2]=x.a[2][3]=1;
	x.a[2][2]=x.a[3][3]=1;
	for(;y;x=mul(x,x),y>>=1) 
	if(y&1) ans=mul(ans,x);
	return;
}
inline LL ksm(LL x,LL y,LL p)//快速幂
{
	LL ans=1;
	for(;y;x=ksc(x,x,p),y>>=1) if(y&1) ans=ksc(ans,x,p);
	return ans;
}
signed main()
{
	n=read();p=read();
	n--;
	jzksm(n);
	write(ksm(ans.a[0][3],n+2,p));//输出
}

猜你喜欢

转载自blog.csdn.net/xuxiayang/article/details/84675376
今日推荐