传送门
思路:
由题意可知:相邻两行要么相同,要么相反;
假设上述命题为假命题,
那么一定存在a[ i ][ j ] != a[ i ][ j+1 ] , a[ i+1 ][ j ] == a[ i+1 ][ j+1 ] ;
由于要么为黑、要么为白(每个格子只有两种状态)
则这四个格子中一定有一个格子有两个相同颜色的相邻格子,
与题目要求矛盾,
因此上述命题为真命题;
得证。
分析一下第一行的情况,如果第一行存在有相邻的两个格子颜色相同,那么第二行也一定相反,同理第三行和第二行相反。上述第一行的这种排列对ans的贡献值是1,即一种这样的排列代表一种合法矩阵。
设 f[ i ][ j ] ,j=0或者1
表示以颜色 j 结尾的长度为 i 的合法排列个数,
则可以得到
f[ i ][ 0 ] = f [ i - 1 ][ 1 ] + f[ i - 2][ 1 ]; 在…1后面补一个0或者两个0
f[ i ][ 1 ] = f [ i - 1 ][ 0 ] + f[ i - 2][ 0 ]; 同理
【也可以把上面两个递推式合并成一个(叠加)】
第一种的情况 为 f [ n ][ 0 ] + f[ n ][ 1 ] - 2 ,
-2 是因为 10101010101和 01010101010这两种序列不属于第一种情况需要减掉 (容斥原理)
第二种情况即为第一行为0101010或者1010101010 这两个排列:
此时第二行可以和第一行相同,也可以不同;
如果第二行和第一行相同,那么第三行必定不同;第二行与第一行不同,那么第三行可与第二行相同可以不同
……
这个时候其实只要确定行首元素就能够确定整个序列了,(要么是101010,要么是010101),即相当于计算第一列的合法排列数: f[ m ][ 1 ] + f[ m ][ 0 ];
AC代码
#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N=1e6+5;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
#define ls (i<<1)
#define rs (i<<1|1)
#define fi first
#define se second
#define mk make_pair
#define mem(a,b) memset(a,b,sizeof(a))
LL read()
{
LL x=0,t=1;
char ch;
while(!isdigit(ch=getchar())) if(ch=='-') t=-1;
while(isdigit(ch)){ x=10*x+ch-'0'; ch=getchar(); }
return x*t;
}
LL f[N][2];
int main()
{
LL n=read(),m=read();
f[1][1]=f[1][0]=1;
f[2][1]=f[2][0]=2;
for(int i=3;i<=max(n,m);i++)
{
f[i][1]=f[i-1][0]+f[i-2][0];
f[i][0]=f[i-1][1]+f[i-2][1];
f[i][1]%=mod; f[i][0]%=mod;
}
printf("%lld
",(f[n][0]+f[n][1]+f[m][0]+f[m][1]-2)%mod);
return 0;
}
其实这道题数据范围应该能再大一点,然后用矩阵快速幂加速即可。