GYM 100827 F.Knights(dp+矩阵快速幂)

来源:互联网 发布:电路图画图软件有几种 编辑:程序博客网 时间:2024/05/17 09:17

Description
一个m*n棋盘,可以在上面放若干马,问有多少中放法使得马之间不会互相冲突
Input
第一行一整数T表示用例组数,每组用例输入两个整数m和n分别表示棋盘的行列数(1<=T<=10,1<=m<=4,1<=n<=1e9)
Output
对于每组用例输出合法方案数
Sample Input
4
1 2
2 2
3 2
4 31415926
Sample Output
4
16
36
413011760
Solution
在第i列放马只会影响第i+1和i+2列(前面的列不会影响,因为这个位置能放马说明没有被前面的影响到 ),那么只要推出i,i+1两列到i+1,i+2两列的状态转移矩阵再矩阵快速幂即可,状态转移矩阵也比较好推,三列只有至多十二个位置,4096种状态,每次看i,i+1这两列的状态x是否能够转移到i+1,i+2这两列的状态y,只需要把这三行的马放好之后判断即可,合法那么A[x][y]=1,否则A[x][y]=0
Code

#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>#include<cmath>#include<vector>#include<queue>#include<map>#include<set>#include<ctime>using namespace std;typedef long long ll;#define maxn 256#define mod 1000000009llstruct Mat{    int mat[maxn][maxn];//矩阵     int row,col;//矩阵行列数 };Mat mod_mul(Mat a,Mat b,ll p)//矩阵乘法 {    Mat ans;    ans.row=a.row;    ans.col=b.col;    memset(ans.mat,0,sizeof(ans.mat));    for(int i=0;i<ans.row;i++)              for(int k=0;k<a.col;k++)            if(a.mat[i][k])                for(int j=0;j<ans.col;j++)                {                    ans.mat[i][j]+=1ll*a.mat[i][k]*b.mat[k][j]%p;                    ans.mat[i][j]%=p;                }    return ans;}Mat mod_pow(Mat a,int k,ll p)//矩阵快速幂 {    Mat ans;    ans.row=a.row;    ans.col=a.col;    for(int i=0;i<a.row;i++)        for(int j=0;j<a.col;j++)            ans.mat[i][j]=(i==j);    while(k)    {        if(k&1)ans=mod_mul(ans,a,p);        a=mod_mul(a,a,p);        k>>=1;    }    return ans;}int T,n,m,a[5][5];void deal(int x){    for(int i=0;i<3*m;i++)        if(x&(1<<i))a[i/m][i%m]=1;        else a[i/m][i%m]=0;}int dx[]={-2,-2,-1,-1,1,1,2,2};int dy[]={-1,1,-2,2,-2,2,-1,1};bool check(){    for(int i=0;i<3;i++)        for(int j=0;j<m;j++)            if(a[i][j])                for(int k=0;k<8;k++)                {                    int ii=i+dx[k],jj=j+dy[k];                    if(ii<0||ii>=3||jj<0||jj>=m)continue;                    if(a[ii][jj])return 0;                }    return 1;}Mat A,B;int main(){    scanf("%d",&T);    while(T--)    {        scanf("%d%d",&m,&n);        if(n==1)        {            printf("%d\n",1<<m);            continue;        }        int M=1<<(2*m),N=1<<(3*m);        B.row=M,B.col=1;        for(int i=0;i<M;i++)        {            deal(i);            B.mat[i][0]=check();        }        A.row=A.col=M;        memset(A.mat,0,sizeof(A.mat));        for(int i=0;i<N;i++)        {            int x=i>>m,y=i&(M-1);            deal(i);            if(check())A.mat[x][y]=1;        }        A=mod_pow(A,n-2,mod);        A=mod_mul(A,B,mod);        ll ans=0;        for(int i=0;i<M;i++)ans=(ans+A.mat[i][0])%mod;        printf("%I64d\n",ans);    }    return 0;}
0 0
原创粉丝点击