题意:
给定三个参数 b(b<1e100),n(n<5),mod(mod<10000),行数为n列数为b 的0,1 矩阵中有多少个不含--- 边长为2且四个点颜色相同(全1或全0)的正方形。结果对mod取模。
思路:
从任意列状态出发,找到一个可以匹配的列状态,得到转移,那么如果一个状态成功转移b-1次,就是该问题的一个可行解。
由于n很小,列状态最多32个,可以先构造转移矩阵,A(n,n)。其中a(i,j)代表i状态可以与j匹配。显然该矩阵为对称矩阵。
那么A*A中每个元素代表的含义有是什么?
显然每个点 b(i,j) 是有a的第i行和第j列相乘得来的,第i行的每个元素可以定义为 :(经过0次转移,最终经由k转移至i有a(i,k)种方案)
那么A^(b-1)中每个元素a(i,j)的含义就是(经过b-1次转移,最终经由k转移至i有a(i,k)种方案)
该题目就是最终的矩阵元素求和。
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
#define rep(i,n) for(int i=0;i<n;i++)
int mod;
const int maxn = 33;
struct Matrix{
int m[maxn][maxn];
void init(){
for(int i=0;i<33;i++)
for(int j=0;j<33;j++)
m[i][j]=(i==j);
}
void show(int lim){
rep(i,lim){
rep(j,lim) cout<<m[i][j]<<" ";
cout<<endl;
}
}
};
string div2(string s){
string ans;
int cnt=0;
for(int i=0;i<s.length();i++){
char c=(s[i]-'0'+cnt*10)/2+'0';
cnt=(cnt*10+s[i]-'0')%2;
if(!ans.empty()||c!='0') ans+=c;
}
if(ans.empty()) ans+='0';
return ans;
}
int mod2(string s){
int res=0;
for(int i=0;i<s.size();i++)
res=(res*10+s[i]-'0')%2;
return res;
}
string sub1(string s){
int res=0;
for(int i=s.size()-1;i>=0;i--){
if(s[i]=='0') s[i]='9';
else{
s[i]--; break;
}
}
if(s[0]=='0') s=s.substr(1);
return s;
}
int n;
Matrix mult(Matrix A,Matrix B){
Matrix C;
for(int i=0;i<(1<<n);i++)
for(int j=0;j<(1<<n);j++){
C.m[i][j]=0;
for(int k=0;k<(1<<n);k++)
C.m[i][j]=(C.m[i][j]+A.m[i][k]*B.m[k][j])%mod;
}
return C;
}
Matrix Pow(Matrix A,string b){
Matrix res;
res.init();
while(b!="0"){
if(mod2(b)) res=mult(res,A);
A=mult(A,A);
b=div2(b);
}
return res;
}
char b[110];
int main()
{
int T;
scanf("%d",&T);
while(T--){
scanf("%s %d %d",b,&n,&mod);
string ss(b); ss=sub1(ss);
Matrix A;
for(int i=0;i<(1<<n);i++)
for(int j=0;j<(1<<n);j++){
A.m[i][j]=1;
for(int k=0;k<n-1;k++){
if(((i>>k)&1) && ((j>>k)&1) && ((i>>(k+1))&1) && ((j>>(k+1))&1)) A.m[i][j]=0;
if(!((i>>k)&1) && !((j>>k)&1) && !((i>>(k+1))&1) && !((j>>(k+1))&1)) A.m[i][j]=0;
}
}
Matrix res=Pow(A,ss);
int sum=0;
rep(i,(1<<n)) rep(j,(1<<n)) sum=(sum+res.m[i][j])%mod;
cout<<sum<<endl;
if(T) cout<<endl;
}
return 0;
}