题意
给你一个 n ∗ m n * m n∗m的方格,问你有多少种方式可以将方格染成黑色和白色的,而且相邻的方格最多有两个颜色相同.
分析与解答
(非官方思路,想的比较繁琐)
首先我们考虑只有一排的方格,定义dp数组如下:
d
p
[
i
]
[
1
]
[
1
]
dp[i][1][1]
dp[i][1][1]为前
i
i
i个第
i
i
i染色为黑色,且第
i
i
i个为单独一个黑色的方案数
d
p
[
i
]
[
0
]
[
1
]
dp[i][0][1]
dp[i][0][1]为前
i
i
i个第
i
i
i染色为白色,且第
i
i
i个为单独一个白色的方案数
d
p
[
i
]
[
1
]
[
2
]
dp[i][1][2]
dp[i][1][2]为前
i
i
i个第
i
i
i染色为黑色,且第
i
i
i个为连续两个黑色的方案数
d
p
[
i
]
[
0
]
[
2
]
dp[i][0][2]
dp[i][0][2]为前
i
i
i个第
i
i
i染色为白色,且第
i
i
i个为连续两个白色的方案数
转移方程如下:
d
p
[
i
]
[
1
]
[
1
]
=
d
p
[
i
]
[
0
]
[
1
]
+
d
p
[
i
]
[
0
]
[
2
]
dp[i][1][1] = dp[i][0][1] + dp[i][0][2]
dp[i][1][1]=dp[i][0][1]+dp[i][0][2]
d
p
[
i
]
[
0
]
[
1
]
=
d
p
[
i
]
[
1
]
[
1
]
+
d
p
[
i
]
[
1
]
[
2
]
dp[i][0][1] = dp[i][1][1] + dp[i][1][2]
dp[i][0][1]=dp[i][1][1]+dp[i][1][2]
d
p
[
i
]
[
1
]
[
2
]
=
d
p
[
i
]
[
1
]
[
1
]
dp[i][1][2] = dp[i][1][1]
dp[i][1][2]=dp[i][1][1]
d
p
[
i
]
[
0
]
[
2
]
=
d
p
[
i
]
[
0
]
[
1
]
dp[i][0][2] = dp[i][0][1]
dp[i][0][2]=dp[i][0][1]
那么第
1
∗
i
1*i
1∗i方格的染色方案数为
a
n
s
[
i
]
=
d
p
[
i
]
[
1
]
[
1
]
+
d
p
[
i
]
[
1
]
[
2
]
+
d
p
[
i
]
[
0
]
[
1
]
+
d
p
[
i
]
[
0
]
[
2
]
ans[i] = dp[i][1][1] + dp[i][1][2] + dp[i][0][1] + dp[i][0][2]
ans[i]=dp[i][1][1]+dp[i][1][2]+dp[i][0][1]+dp[i][0][2]
接下来考虑多排的问题.
我们注意到如果第一排出现两个相同颜色的情况假设为
i
i
i和
i
+
1
i + 1
i+1,我们考虑第二排这两个位置的放置方法,如果我们放置任何一个与第一排颜色不同的那么组成了三个颜色相同的连续的方块,因此我们必须放置与第一排颜色不同的两个方块,同时我们考虑从这两个位置向两侧延展,那么
i
+
2
i+2
i+2位置,必须放置与第一排颜色不同的块,
i
+
3
i+3
i+3位置也只能放置与第一排颜色不同的,以此类推,可得如果第一排有两个连续的相同方块第二排必须每个都与第一排颜色不同.这种情况下的方案数为
a
n
s
[
m
]
−
2
ans[m] - 2
ans[m]−2
如果第一排没有连续两个颜色相同的,我们按照同样的推理方法我们可以得到,同一排相邻两个颜色必须不同.因此只要确定了第一列的放置就可以推出所有的排列方案,而第一列的放置不受约束,这种情况的方案数为
a
n
s
[
n
]
ans[n]
ans[n]
综上,最后的答案为
a
n
s
[
m
]
−
2
+
a
n
s
[
n
]
ans[m] - 2 + ans[n]
ans[m]−2+ans[n]
代码
/*************************************************************************
> File Name: 2019_10_20_3.cpp
> Author: z472421519
> Mail:
> Created Time: 2019年10月20日 星期日 17时45分14秒
************************************************************************/
#include <bits/stdc++.h>
#include <cstdio>
#include <cstring>
#define MAXN 100003
#define LL long long
const LL mod = 1e9 + 7;
using namespace std;
LL mul(LL a,LL b)
{
LL ans=0;
while(b)
{
if(b&1) ans=(ans+a)%mod;
b>>=1;
a=(a%mod+a%mod)%mod;
}
return ans;
}
LL dp[MAXN][3][3];
LL sum[MAXN];
int main()
{
int n,m;
scanf("%d%d",&n,&m);
dp[1][1][1] = dp[1][0][1] = 1ll;
dp[1][1][2] = dp[1][0][2] = 0ll;
sum[1] = 2ll;
for(int i = 2;i <= 100000;i++)
{
dp[i][1][1] = (dp[i - 1][0][1] + dp[i - 1][0][2]) % mod;
dp[i][0][1] = (dp[i - 1][1][1] + dp[i - 1][1][2]) % mod;
dp[i][1][2] = dp[i - 1][1][1] % mod;
dp[i][0][2] = dp[i - 1][0][1] % mod;
sum[i] = (dp[i][1][1] + dp[i][1][2] + dp[i][0][1] + dp[i][0][2]) % mod;
}
//printf("%lld\n",sum[3]);
cout << ((sum[m] - 2 + mod) + sum[n]) % mod;
}