题意
一个n*m的网格图,每个格子可以染黑色、白色,问你每个格子最多有一个相邻颜色相同的方案数
n,m<=1e5
思路
我们先处理(1 imes m)的情况
设(f[i][j])为前(i)个格子,最后一个为(j)的方案数
可以得到递推式(f[i][j]=f[i-1][jigoplus 1]+f[i-2][jigoplus 1])
那么(1 imes m)的答案为(f[m][0]+f[m][1])
引理
这题中的合法的染色图相邻两行要么完全相同,要么完全相反
证明:
假设第(i)行和第(i+1)行部分相同,部分相反,设白色是(0),黑色是(1)
那么就存在一个位置(j),使得(a[i+1][j]=a[i][j],a[i+1][j+1]!=a[i][j+1])(先不等后相等一样)
因为这四个方格可选的颜色只有两个,所以在(a[i+1][j+1])和(a[i][j+1])中一定有一个和(a[i+1][j])与(a[i][j+1])相同
也就是说,这四个方格中出现了三个一样的颜色,无论怎么组合都不满足题意,
所以不存在部分相同部分相反,引理得证
有了以上结论,我们可以可以找"什么时候完全相同,什么时候完全相反"了
可以发现,当一行里存在连续两个连续一样的颜色的时候,下一行一定与该行相反
也就是说,如果确定了第一行,里面有两个连续一样的颜色,对答案的贡献为1
第一行的这种情况方案数为(f[m][0]+f[m][1]-2)
而排除的这两种,就是第一行为(10101010..)和(01010101..)两种方案
由于引理的存在,我们可以知道,当每一行的第一个元素确定的时候,我们就确定了这行跟上一行完全相同还是相反
所以这种情况的贡献就是第一列的合法方案数,即(f[n][0]+f[n][1])
终上所述,答案为(f[m][0]+f[m][1]+f[n][0]+f[n][1]-2)
代码
ll n,m;
ll f[maxn][3];
ll F[maxn];
int main(){
scanf("%lld %lld", &n, &m);
f[1][0]=f[1][1]=1;
f[2][0]=f[2][1]=2;
F[1]=2;F[2]=4;
for(int i = 3; i <= max(n,m); i++){
f[i][1]=(f[i-1][0]+f[i-2][0])%mod;
f[i][0]=(f[i-1][1]+f[i-2][1])%mod;
F[i]=(f[i][0]+f[i][1])%mod;
}
printf("%lld",(F[n]+F[m]-2+mod)%mod);
return 0;
}