一名苦逼的OIer,想成为ACMer

Iowa_Battleship

洛谷1373 小a和uim之大逃离

原题链接

只要想好状态,这题就是水题了,转移方程完全没难度。。
\(f[i][j][w][u]\)表示走到\((i, j)\)格,小\(a\)\(uim\)所取得魔力值的差值为\(w\),该格由(\(u = 0\)则小\(a\)取,\(u = 1\)\(uim\)取)时的总方案数。
设格子\((i, j)\)的魔力值为\(a[i][j]\),则有状态转移方程:

\(\qquad\qquad f[i][j][w][0] = f[i][j][w][0] + f[i - 1][j][v][1] + f[i][j - 1][v][1],\quad v = (w - a[i][j] + k + 1) \% (k + 1)\)

\(\qquad\qquad f[i][j][w][1] = f[i][j][w][1] + f[i - 1][j][v][0] + f[i][j - 1][v][0],\quad v = (w + a[i][j]) \% (k + 1)\)

因为小\(a\)能从任意一个格子开始走,所以初值为\(i = 1 \to n, j = 1 \to m, f[i][j][a[i][j]][0] = 1\)
最后答案为\(\sum\limits_{i = 1}^n\sum\limits_{j = 1}^m f[i][j][0][1]\)

#include<cstdio>
using namespace std;
const int N = 810;
const int M = 16;
const int mod = 1e9 + 7;
int f[N][N][M][2], a[N][N];
inline int re()
{
	int x = 0;
	char c = getchar();
	bool p = 0;
	for (; c < '0' || c > '9'; c = getchar())
		p |= c == '-';
	for (; c >= '0' && c <= '9'; c = getchar())
		x = x * 10 + c - '0';
	return p ? -x : x;
}
inline long long MOD(long long x)
{
	if (x < mod)
		return x;
	return x - mod;
}
int main()
{
	int i, j, n, m, k, o, w, v, s = 0;
	n = re();
	m = re();
	k = re();
	o = k + 1;
	for (i = 1; i <= n; i++)
		for (j = 1; j <= m; j++)
		{
			a[i][j] = re();
			f[i][j][a[i][j]][0] = 1;
		}
	for (i = 1; i <= n; i++)
		for (j = 1; j <= m; j++)
			for (w = 0; w <= k; w++)
			{
				v = (w - a[i][j] + o) % o;
				f[i][j][w][0] = MOD(MOD(1LL * f[i - 1][j][v][1] + f[i][j - 1][v][1]) + f[i][j][w][0]);
				v = (w + a[i][j]) % o;
				f[i][j][w][1] = MOD(MOD(1LL * f[i - 1][j][v][0] + f[i][j - 1][v][0]) + f[i][j][w][1]);
				if (!w)
					s = MOD(1LL * s + f[i][j][0][1]);
			}
	printf("%d", s);
	return 0;
}

posted on 2018-10-22 14:36  Iowa_Battleship  阅读(95)  评论(0编辑  收藏  举报

导航