看到题就想起以前做过的类似多米诺骨牌相关的题目,想着应该是有递推式的,菜鸟的我就开始画图,画到废了废了,之后借助网上大佬博客的递推演算:
行数为4
当n=2时,方案数为5;
当n>2时,方案数可由5种情况组合:
第一种情况(第一列填充满): num1=f[n-1];
第二种情况(前两列填充满): num2=f[n-2];
第三种情况(根据列填充满判断): num3=f[n-2]+f[n-3]+……+f[0];
第四种情况同第三种: num4=num3;
第五种情况判断方法同第三种: num5=f[n-2]+f[n-4]+……+f[0]/f[1];
所以:f[n]=num1+num2+num[3]+num[4]+num[5];
因为第五种中存在两种情况,为了避免,采取f[n]-f[n-2],整理可得:
f[n]=f[n-1]+5f[n-2]+f[n-3]-f[n-4];
再利用矩阵快速模幂求解,注意负数模幂先加上mod
1≤n≤10181
/*矩阵快速幂*/
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int N=4;
struct Matrix{//矩阵结构体
ll a[16][16];
void init(){ //初始化为单位矩阵
memset(a,0,sizeof(a));
for(int i=0;i<N;i++)
a[i][i]=1;
}
};
Matrix g,ans,tmp;
Matrix matrix(Matrix x,Matrix y){//矩阵乘法
for(int i=0;i<N;i++)
for(int j=0;j<N;j++){
tmp.a[i][j]=0;
for(int k=0;k<N;k++)
tmp.a[i][j]=(tmp.a[i][j]+x.a[i][k]*y.a[k][j]+mod)%mod; //+mod 负数取模
}
return tmp;
}
void qpow(ll n){//矩阵快速幂
ans.init();
Matrix t=g;
while(n){
if(n&1)
ans=matrix(ans,t);
n>>=1;
t=matrix(t,t);
}
}
int main()
{
ll n;
while(~scanf("%lld",&n))
{
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
{
memset(g.a,0,sizeof(g.a));
g.a[0][0]=1; g.a[0][1]=5; g.a[0][2]=1; g.a[0][3]=-1;
g.a[1][0]=1;
g.a[2][1]=1;
g.a[3][2]=1;
qpow(n-4);
printf("%lld\n",(ans.a[0][0]*36l%mod+ans.a[0][1]*11l%mod+ans.a[0][2]*5l%mod+ans.a[0][3])%mod);
}
}
return 0;
}
可以借助暴力搜索得出前几个数据再进行找规律(这个提交会TL)
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <string>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
int mp[15][15];
int vis[15][15];
int n;
ll sum=0;
int cnt=0;
bool safe(int x, int y) { //是否越界
if (x>=0&&x<4&&y>=0&&y<n&&!vis[x][y]) return 1;
return 0;
}
bool check() { //是否结束
for (int i=0; i<4; i++) {
for (int j=0; j<n; j++) {
if (!vis[i][j]) {
return 0;
}
}
}
return 1;
}
int findx() { //找未搜索点的横坐标
for (int i=0; i<4; i++) {
for (int j=0; j<n; j++) {
if (!vis[i][j]) {
return i;
}
}
}
return -1;
}
int findy() { //找未搜索点的纵坐标
for (int i=0; i<4; i++) {
for (int j=0; j<n; j++) {
if (!vis[i][j]) {
return j;
}
}
}
return -1;
}
void dfs(int x, int y) {
for (int k=0; k<2; k++) {
if (k==0) { //用2*1规格的,标记为2
if(safe(x,y)&&safe(x+1,y)) { //范围内
vis[x][y]=2, vis[x+1][y]=2;
if (check()) { //搜索结束
sum++;
vis[x][y]=0, vis[x+1][y]=0;
}
else { //未结束,继续搜索
int xx=findx(), yy=findy();
if(xx!=-1&&yy!=-1) {
vis[x][y]=2, vis[x+1][y]=2;
dfs(xx,yy);
vis[x][y]=0, vis[x+1][y]=0;
}
}
}
}
if (k==1) { //用1*2规格的,标记为1
if (safe(x,y)&&safe(x,y+1)) {
vis[x][y]=1, vis[x][y+1]=1;
if (check()) {
sum++;
vis[x][y]=0, vis[x][y+1]=0;
}
else {
vis[x][y]=1, vis[x][y+1]=1;
int xx=findx(), yy=findy();
if(xx!=-1&&yy!=-1) {
dfs(xx,yy);
vis[x][y]=0, vis[x][y+1]=0;
}
}
}
}
}
}
int main() {
while(~scanf("%d",&n)){
sum=0,cnt=0;
memset(vis, 0, sizeof(vis));
dfs(0, 0);
printf("%lld\n",sum);
}
return 0;
}