luogu1373 小a和uim之大逃离

题目大意

  地面上出现了一个n*m的巨幅矩阵,矩阵的每个格子上有一坨0~k不等量的魔液。怪物各给了小a和uim一个魔瓶,说道,你们可以从矩阵的任一个格子开始,每次向右或向下走一步,从任一个格子结束。开始时小a用魔瓶吸收地面上的魔液,下一步由uim吸收,如此交替下去,并且要求最后一步必须由uim吸收。魔瓶只有k的容量,也就是说,如果装了k+1那么魔瓶会被清空成零,如果装了k+2就只剩下1,依次类推。问使两个人内的魔瓶内的魔液一样多的走法有多少种。

题解

  我们很容易想到动规。用f(i, j, t, k, p)表示在位置(i, j),小a瓶子里有t个魔液,uim瓶子里有k个魔液,p表示当前轮到小a还是uim。一开始我想枚举每一个起始点然后动规,这样的时间复杂度是$O(n^2 m^2 k)$的,这种转移的过程让我在潜意识里认为这道题就应该用Bfs解决,以至于随后想到可以将所有出发点一起整时就是n*m个Bfs同时做,时间复杂度$O(n^2m^2)$。请你想想,这究竟是动规还是暴力呀?

  正确做法是:t和k可以转化为小a和uim瓶子里的液体的差d,这就降了一维;随后我们列出递归式来,根据递归式老老实实刷表即可。

  一些卡常数:要mod K,请(x + k) % k即可,不要(x % k + k) % k,这就慢了;同时,也不要为了取模单独写一个函数,函数调用费时间。

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

const int MAX_ROW = 810, MAX_COL = 810, MAX_K = 20;
const long long P = 1000000007;
int TotRow, TotCol, K;
int A[MAX_ROW][MAX_COL];

long long DP()
{
	static int F[MAX_ROW][MAX_COL][MAX_K][2];
	K++;
	for (int row = 1; row <= TotRow; row++)
		for (int col = 1; col <= TotCol; col++)
			F[row][col][A[row][col]][0] = 1;
	for (int row = 1; row <= TotRow; row++)
		for (int col = 1; col <= TotCol; col++)
			for (int t = 0; t < K; t++)
			{
				//当前是小a,下一个是uim
				F[row + 1][col][(t - A[row + 1][col] + K) % K][1] += F[row][col][t][0];
				F[row + 1][col][(t - A[row + 1][col] + K) % K][1] %= P;
				F[row][col + 1][(t - A[row][col + 1] + K) % K][1] += F[row][col][t][0];
				F[row][col + 1][(t - A[row][col + 1] + K) % K][1] %= P;
				//当前是uim,下一个是小a
				F[row + 1][col][(t + A[row + 1][col] + K) % K][0] += F[row][col][t][1];
				F[row + 1][col][(t + A[row + 1][col] + K) % K][0] %= P;
				F[row][col + 1][(t + A[row][col + 1] + K) % K][0] += F[row][col][t][1];
				F[row][col + 1][(t + A[row][col + 1] + K) % K][0] %= P;
			}
	long long ans = 0;
	for (int row = 1; row <= TotRow; row++)
		for (int col = 1; col <= TotCol; col++)
			ans = (ans + F[row][col][0][1]) % P;
	return ans;
}

int main()
{
	scanf("%d%d%d", &TotRow, &TotCol, &K);
	for (int i = 1; i <= TotRow; i++)
		for (int j = 1; j <= TotCol; j++)
			scanf("%d", &A[i][j]);
	printf("%lld
", DP());
	return 0;
}

  

原文地址:https://www.cnblogs.com/headboy2002/p/9529723.html