P2049 魔術棋子 題解

2022-02-14 14:34:04 字數 1367 閱讀 4725

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,開始從左上角進入棋盤,走到右下角,上圖...