洛谷 P1373 小a和uim之大逃離

傳送門

思路

吐槽

吐槽:話說不應該是他倆都得死嘛qwq

咋做

一道DPDP好題.

我們用f[i][j][q][p]f[i][j][q][p]來表示:走到第ii行第jj列魔液差距值爲qq且當前爲pp走的方案數(p{0,1}p=0p\in \{0, 1\} p=0表示目前爲小aa走,p=1p=1表示目前爲uimuim走)

初始條件:f[i][j][a[i][j]][0]=1f[i][j][a[i][j]][0]=1表示小aa從每個點開始取,差距值爲a[i][j]a[i][j]的方案數爲11

那麼我們可以想出轉移方程:

f[i][j][p][0]+=f[i1][j][pa[i][j]][1]+f[i][j1][pa[i][j]][1]f[i][j][p][0]+=f[i-1][j][p-a[i][j]][1]+f[i][j-1][p-a[i][j]][1]

這個式子表示目前在第ii行第jj列,差距值爲pp,當前小aa走的方案數,因爲只能往右走或往下走,且上一步一定是uimuim走的,所以可以從第i1i-1行第jj列、第ii行第j1j-1列轉移過來,差距值增大

f[i][j][p][1]+=f[i1][j][p+a[i][j]][0]+f[i][j1][pa[i][j]][0]f[i][j][p][1]+=f[i-1][j][p+a[i][j]][0]+f[i][j-1][p-a[i][j]][0]

同理,這個式子表示目前在第ii行第jj列,差距值爲pp,當前uimuim走的方案數,上一步一定是小aa走的,所以可以從第i1i-1行第jj列、第ii行第j1j-1列轉移過來,差距值減小

我們容易想出,最後的答案就是i=1nj=1mf[i][j][0][1]\sum_{i = 1}^{n}\sum_{j = 1}^{m}f[i][j][0][1]最後一維是11是因爲最後一步只能由uimuim

空間複雜度nmk2n*m*k*2剛好可以,時間複雜度O(nmk)O(n*m*k)可以過

注意!

  1. 因爲魔液值到達k+1k+1之後就會清00,所以在過程中要隨時對k+1k+1取模
  2. 空間開好!!不要開太大!因爲最後一維只用010、1,所以開22的數組就好了就行了,開33MLEMLE
  3. 碼風醜陋,謹慎閱讀qwqqwq

代碼

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int B = 20;
const int A = 800 + 7;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;

inline int read() {
	char c = getchar(); int x = 0, f = 1;
	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
	return x * f;
}

int n, m, k, a[A][A], f[A][A][B][2];

int main() {
	n = read(), m = read(), k = read() + 1;
	for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) a[i][j] = read(), f[i][j][a[i][j] % k][0] = 1;
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= m; j++)
			for(int p = 0; p <= k; p++) {
				f[i][j][p][0] = (f[i][j][p][0] + f[i - 1][j][(p - a[i][j] + k) % k][1] + f[i][j - 1][(p - a[i][j] + k) % k][1]) % mod;
				f[i][j][p][1] = (f[i][j][p][1] + f[i - 1][j][(p + a[i][j] + k) % k][0] + f[i][j - 1][(p + a[i][j] + k) % k][0]) % mod;
			}
	int ans = 0;
	for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) ans += f[i][j][0][1], ans %= mod;
	cout << ans << '\n';
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章