csdn同步
原題鏈結
簡要題意:
在乙個 \(n \times m\) 的魔術棋盤中,每個格仔中均有乙個整數,當棋子走進這個格仔中,則此棋子上的數會被乘以此格仔中的數。乙個棋子從左上角走到右下角,只能向右或向下行動,請問此棋子走到右下角後,模 \(\% k\) 可以為幾?
(原題題意足夠簡要了吧)
\(n,m,k \leq 100\).
考慮乙個很樸素的做法,\(\mathcal(nmk)\) 的那種。
很顯然我們不可能算出所有路徑的答案(\(c_^m\) 種的級別大家應該都清楚),所以說我們可以從答案入手。
列舉乙個答案,看它能不能是合法的答案。
對於 \((i,j) (i > 1 , j > 1)\) 點,其數為 \(a_\),如何驗證 \(a_ \rightarrow l\)(表示走到 \(a_\) 的時候數字為 $l)的正確?
考慮前一步的走法,很顯然,考慮是否有 \(t \times a_ \% k = l\) 且 \(t\) 是 \(a_\) 或 \(a_\) 的合法答案。
好,下一步我們考慮,\(t\) 是否需要用逆元計算?倒推需要逆元,我們可以考慮正推。用當前的答案去更新之後的答案,也是所謂動態規劃的另一種(不太常見的)方式。
所以說動態規劃不止可以是f[i] = ...
的形式,可以是... = f[i] ...
的形式,採用「我從**來」「我到**去」兩種均可。
下面就很簡單了。初步的方案,用 \(h_\) 表示走到 \(a_\) 數字能否為 \(t\). 一開始只有 \(h_} = 1\),考慮如何轉移?很簡單。
\[h_ \% k} = \max(h_})
\]當前想要表示出 \(t \times a_ \% k\) 就去驗證 \(k\),避免了逆元和轉移中記憶化的技巧 ,直奔主題。
時間複雜度:\(\mathcal(nmk)\).
#pragma gcc optimize(2)
#includeusing namespace std;
const int n=1e2+1;
inline int read()
int x=0; while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return x*f;}
inline void write(int x)
if(x<10)
write(x/10);putchar(char(x%10+'0'));
}int n,m,k,a[n][n];
bool h[n][n][n];
int main()
P2049 魔術棋子
在乙個m n的魔術棋盤中,每個格仔中均有乙個整數,當棋子走進這個格仔中,則此棋子上的數會被乘以此格仔中的數。乙個棋子從左上角走到右下角,只能向右或向下行動,請問此棋子走到右下角後,模 mod k可以為幾?如以下2 3棋盤 3 4 4 5 6 6 棋子初始數為1,開始從左上角進入棋盤,走到右下角,上圖...
洛谷 P2049 魔術棋子
乙個比較簡單dp問題。我們先來分析一下題目,要找到所有的模的總數,首先可以想到,用dp i j 表示在 i,j 這個點所有的方案數。但是,這樣顯然不行。因為僅僅知道方案總數對求解下乙個狀態毫無幫助。那麼,我們就要記錄每乙個點所有可能的模。所以,我們用三維dp i j l 表示在 i,j 點是否能夠得...
洛谷 P2049 魔術棋子
在乙個m n的魔術棋盤中,每個格仔中均有乙個整數,當棋子走進這個格仔中,則此棋子上的數會被乘以此格仔中的數。乙個棋子從左上角走到右下角,只能向右或向下行動,請問此棋子走到右下角後,模 mod k可以為幾?如以下2 3棋盤 3 4 4 5 6 6 棋子初始數為1,開始從左上角進入棋盤,走到右下角,上圖...