這種型別的題(對腦電波題)有些題能秒,有些題想多久都想不出來。。。
顯然本題能一起染黑的邊存在某種關係,我們考慮一條邊可以和哪兩條邊一起染色,乍一看如果還沒看出來有什麼性質,我們就考慮把連著的邊再這樣考慮一遍。
突然,靈光乍現!我們這樣連可以連出來個斜線!也就是說我們可以將網格圖拆開,分開討論每一個斜線。我們把每個斜線拉直變成序列,發現這顯然可以 dp 處理,設 \(f_{i,0}\) 表示到第 \(i\) 位末尾有偶數個點染黑, \(f_{i,1}\) 表示到第 \(i\) 位末尾有奇數個點染黑,轉移非常 easy:
\[f_{i,0}=f_{i-1,0}+f_{i-1,1}
\]
\[f_{i,1}=f_{i-1,0}
\]
然後我們再回到網格圖,手玩一下就會發現分開的斜線含有的邊的數量是一個類似分段函式的東西,不妨設 \(n<m\),前 \(n\) 條斜線的長度是差為 \(2\) 的等差數列,後面有 \(m-n\) 條長度為 \(2n+1\) 的斜線,再往後有跟第一段等價的一段。
那麼我們預處理出累乘的值,每次詢問再用快速冪算出第二段的值就做完啦!
時間複雜度 \(\mathcal{O}(n+T\log n)\)。
程式碼:
int f[N][2], g[N];
signed main ()
{
f[0][0] = 1;
g[0] = 1;
rep (i, 1, N - 1) f[i][0] = (f[i - 1][0] + f[i - 1][1]) % P, f[i][1] = f[i - 1][0];
rep (i, 1, N - 1) if (i & 1) g[i + 1] = g[i - 1] * f[i + 1][0] % P;
int T = rd ();
for (; T; -- T)
{
int n = rd (), m = rd ();
if (n > m) swap (n, m);
printf ("%lld\n", g[n * 2] * g[n * 2] % P * qpow (f[n * 2 + 1][0], m - n) % P);
}
}