描述
小 D 特別喜歡玩游戲。這一天,他在玩一款填數游戲。
這個填數游戲的棋盤是一個n × m的矩形表格。玩家需要在表格的每個格子中填入一個數字(數字 0 或者數字 1),填數時需要滿足一些限制。
下面我們來具體描述這些限制。
為了方便描述,我們先給出一些定義:
? 我們用每個格子的行列坐標來表示一個格子,即(行坐標,列坐標)。(注意:行列坐標均從 0 開始編號)
? 合法路徑 P:一條路徑是合法的當且僅當:
這條路徑從矩形表格的左上角的格子(0,0)出發,到矩形的右下角格子(n ? 1, m ? 1)結束;
在這條路徑中,每次只能從當前的格子移動到右邊與它相鄰的格子,或者從當前格子移動到下面與它相鄰的格子。
例如:在下面這個矩形中,只有兩條路徑是合法的,它們分別是?1:(0,0) → (0,1) →(1,1)和?2:(0,0) → (1,0) → (1,1)。
對于一條合法的路徑 P,我們可以用一個字符串w§來表示,該字符串的長度為n +m ? 2,其中只包含字符“R”或者字符“D”,第 i 個字符記錄了路徑 P 中第 i 步的移動方法,“R”表示移動到當前格子右邊與它相鄰的格子,“D”表示移動到當前格子下面與它相鄰的格子。例如,上圖中對于路徑?1,有w(P1) = “RD”;而對于另一條路徑?2,有w(P2) = “DR”。
同時,將每條合法路徑 P 經過的每個格子上填入的數字依次連接后,會得到一個長度為n + m ? 1的 01 字符串,記為 s§。例如,如果我們在格子(0,0)和(1,0)上填入數字0,在格子(0,1)和(1,1)上填入數字 1(見上圖紅色數字)。那么對于路徑?1,我們可以得到s(P1) = “011”,對于路徑?2,有s(P2) = “001”。
游戲要求小 D 找到一種填數字 0、1 的方法,使得對于兩條路徑?1,P2,如果w(P1) >w(P2),那么必須s(P1) ≤ s(P2)。我們說字符串 a 比字符串 b 小,當且僅當字符串 a 的字典序小于字符串 b 的字典序,字典序的定義詳見第一題。但是僅僅是找一種方法無法滿足小 D 的好奇心,小 D 更想知道這個游戲有多少種玩法,也就是說,有多少種填數字的方法滿足游戲的要求?
小 D 能力有限,希望你幫助他解決這個問題,即有多少種填 0、1 的方法能滿足題目要求。由于答案可能很大,你需要輸出答案對10^9 + 7取模的結果。
輸入
輸入文件共一行,包含兩個正整數 n、m,由一個空格分隔,表示矩形的大小。其中 n 表示矩形表格的行數,m 表示矩形表格的列數。
輸出
輸出共一行,包含一個正整數,表示有多少種填 0、1 的方法能滿足游戲的要求。
注意:輸出答案對 10^9+7 取模的結果。
樣例輸入
2 2
樣例輸出
12
提示
【樣例解釋】
【輸入樣例2】
5 5
【輸出樣例2】
7136
可以顯然看出滿足的首要條件是從左下到右上的任意一條對角線是單調不增的
顯然看出n=2n=2n=2的時候答案是4?3m?14*3^{m-1}4?3m?1
但是3的時候就懵逼了
只能暴力枚舉3以內的然后50分滾粗
因為有這樣一種情況
(1,1),(1,2),(2,2),(3,2),(3,3)(1,1),(1,2),(2,2),(3,2),(3,3)(1,1),(1,2),(2,2),(3,2),(3,3)和(1,1),(2,1),(2,2),(2,3),(3,3)(1,1),(2,1),(2,2),(2,3),(3,3)(1,1),(2,1),(2,2),(2,3),(3,3)這兩條路徑就不行
正解是輪廓線狀壓dp
然而我不會
只能搜索打表
規律是一個三維的等比數列
跑了一下午終于跑出來了233……
上代碼(我也不知道該怎么講了)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod=1e9+7;
int n,m;
inline int read(){char ch=getchar();int res=0;while(!isdigit(ch))ch=getchar();while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();return res;
}
inline ll ksm(ll a,int n){ll res=1;for(;n;n>>=1,a=a*a%mod)if(n&1)res=res*a%mod;return res%mod;
}
int main(){n=read(),m=read();if(n>m)swap(n,m);if(n==1){cout<<ksm(2,m)<<'\n';}if(n==2){cout<<4*ksm(3,m-1)%mod<<'\n';}if(n==3){cout<<112*ksm(3,m-3)%mod<<'\n';}if(n==4){if(m==4)puts("912");else cout<<2688*ksm(3,m-5)%mod<<'\n';}if(n==5){if(m==5)puts("7136");else cout<<21312*ksm(3,m-6)%mod<<'\n';}if(n==6){if(m==6)puts("56768");else cout<<170112*ksm(3,m-7)%mod<<'\n';}if(n==7){if(m==7)puts("453504");else cout<<1360128*ksm(3,m-8)%mod<<'\n';}if(n==8){if(m==8)puts("3626752");else cout<<10879488*ksm(3,m-9)%mod<<'\n';}
}
最后
推廣一下另外幾篇題解:
DAY1T1:鋪設道路:(并查集??)
DAY1T2:貨幣系統:(完全背包/搜索)
DAY1T3:賽道修建:(二分答案+貪心策略)
DAY2T1:旅行:(基環樹搜索)
DAY2T2:填數游戲:(暴力搜索找規律)
DAY2T3:保衛王國:(動態dp+Splay)