Codeforces 1239A. Ivan the Fool and the Probability Theory
注意到连续两个格子如果有相同颜色那么一路过去的都可以确定
比如一开始染了这两个位置:
然后发现后面整片过去都可以确定:
对于横着的情况也是一样,然后就会发现不可能出现横着两个和竖着两个同时都有的情况,因为这样一定会冲突,就一定不合法了
(自己画一下就知道了)
那么现在只要对行列分别计算即可,直接设 $f[i][0/1][0/1]$ 表示前 $i$ 个位置,当前位置为 $0/1$ 上一个位置为 $0/1$ 时的方案数
那么转移十分显然,然后答案就是行任意放的方案 $\sum_{i=0}^{1}\sum_{j=0}^{1}f[n][i][j]$ 加上列任意放的方案 $\sum_{i=0}^{1}\sum_{j=0}^{1}f[m][i][j]$ 减 $2$
减 $2$ 是因为黑白染色情况下的方案会被行和列都算到,要减去多算的次数
然后就可以过了,但是事实上如果直接设 $g[i]=\sum_{i=0}^{1}\sum_{j=0}^{1}f[n][i][j]$ ,然后分析原本 $f$ 的方程,那么你会发现 $g[i]$ 恰好等于 $g[i-1]+g[i-2]$
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; typedef long long ll; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } const int N=2e5+7,mo=1e9+7; inline int fk(int x) { return x>=mo ? x-mo : x; } int n,m,f[N][2][2]; int main() { n=read(),m=read(); int mx=max(n,m); if(n==1&&m==1) { printf("2\n"); return 0; } f[2][0][0]=f[2][0][1]=f[2][1][0]=f[2][1][1]=1; for(int i=3;i<=mx;i++) { f[i][0][0]=f[i-1][0][1]; f[i][0][1]=fk(f[i-1][1][0]+f[i-1][1][1]); f[i][1][0]=fk(f[i-1][0][0]+f[i-1][0][1]); f[i][1][1]=f[i-1][1][0]; } if(n>m) swap(n,m); if(n==1) { printf("%d\n", fk(fk(f[m][0][0]+f[m][0][1]) + fk(f[m][1][0]+f[m][1][1])) ); return 0; } int ans=fk(fk(f[m][0][0]+f[m][0][1]) + fk(f[m][1][0]+f[m][1][1])); ans=fk(ans-2+mo); ans=fk(ans+ fk(fk(f[n][0][0]+f[n][0][1]) + fk(f[n][1][0]+f[n][1][1]))); printf("%d\n",ans); }