题意:给一个n×m的网格,只涂黑白,问再没有三个联通方格的情况下涂色,有多少种涂法?结果mod 1e9+7
直接说解法:
首先判断第一行的情况,做递推关系式F[ i ],F[ 1 ]显然为2,F[ 2 ]也可以任意,显然为4。
接下来F[ 3 ],需要分这个的前两个是否为连续相同的色块,如果是连续相同的色块,那么只能与前一个色块不同。我们把F[i]拓展为F[i][j],i表示到第几个块,j表示第i个的前两个是否为连续两块。那么F[ i ]的种类数分为:
(1):前面是两个连续相同,那么F[ i ]的种数与F[ i - 1 ]的种数相同,且状态变为不连续。即:F[ i ][ 0 ] += F[ i - 1 ] [ 1 ];
(2) :前面两个连续不同,那么当前分为两种情况,继续与前面不同,或与前面相同,状态转为连续。既:F[ i ][ 0 ] += F[ i - 1 ][ 0 ], F[ i ][ 1 ] = F[ i - 1 ][ 0 ];
得出总的递推关系式:
F[ i ] [ 0 ] = F[ i - 1 ] [ 0 ] + F[ i -1 ][ 1];
F[ i ] [ 1 ] = F[ i - 1 ] [ 0 ];
F[ 1 ][ 0 ] = 2; F[ 1 ][ 1 ]=0;
若为i个方块,那么有F[ i ][ 0 ] + F [ i ][ 1 ]种解;
// 其实涂色方式也可以当作N个台阶,每次上1阶或2阶,问有多少种上阶梯方法。
两种理解方式都讲递推关系式指向了斐伯纳契。既推出斐伯纳契的第n项与第m项。
确定第一行后,我们再递推到全部行。
如果第一行有两个连续的色块,那么下面的每一行都必须与上一行完全相反。如果有相同的,那么必然出现3个连续相同的情况。
证明: 若上一行连续两个相同处,下一行不完全相反,那么必然有一个和上一个连续相同两处相同,连成3个
若上一行不连续两个相同处,要有一个与上一行不完全相反
设上一行为黑白黑白黑
那么下一行必然有一个黑对黑或白对白,会与左右相同,连成3个相同。
若完全相同,必然会遇到水平相同两个的与之相连
白黑白白黑
黑白黑黑白
会与上面的二连白相同或下面的二连黑相同
故只有一种下面的结果,每一行与前一行完全相反。
如果第一行没有两个连续相同的色块,既黑白黑白黑白黑白 或 白黑白黑白黑白黑(共计两种),那么接下来的一行可以与本行完全相等,或者完全相反。并且完全相同只能连续两行。这样的每行递推下来也相当于,没有三行连续相同,即和上面一行中推法一样,所以也是斐伯纳契m项的值。因为初始状态只有两种满足没有两个连续相同色块,所以是2×斐伯纳契m
那么结果就是 第一行有连续色块,剩下所有行结果已定。 总数为 2×斐伯纳契第n项-2
第一行无连续色块,剩下种类为斐伯纳契m项,既 2×斐伯纳契第m项
总结果数量为 2×(斐伯纳契n项+斐伯纳契m项)-2
以下为AC代码(比赛时没发现行也是斐伯纳契,所以复杂了点。)
1 #include<iostream> 2 using namespace std; 3 typedef long long ll; 4 const int mod = 1e9+7; 5 const int maxn = 1e5+50; 6 ll dp[maxn][3]; 7 int main(){ 8 int n,m; 9 cin>>n>>m; 10 dp[1][0]=2; 11 dp[1][1]=0; //初始化 12 for(int i=2;i<=n;i++){ //递推 13 dp[i][0]=dp[i-1][0]+dp[i-1][1]; 14 dp[i][1]=dp[i-1][0]; 15 dp[i][0]%=mod; 16 dp[i][1]%=mod; 17 } 18 ll a,b,c; 19 a=0,b=1,c=0; 20 for(int i=0;i<n;i++){ 21 c=a+b; 22 a=b; 23 b=c; 24 c%=mod; 25 } 26 ll res = dp[m][0]+dp[m][1]-2+b*2; //得结果 27 res%=mod; 28 cout<<res<<endl; 29 return 0; 30 }
原文地址:https://www.cnblogs.com/greenpepper/p/11711071.html