51nod 1503 猪和回文(双线DP)

1503 猪和回文
题目来源:  CodeForces
基准时间限制:2 秒 空间限制:131072 KB 分值: 40  难度:4级算法题
 收藏
 关注

一只猪走进了一个森林。很凑巧的是,这个森林的形状是长方形的,有n行,m列组成。我们把这个长方形的行从上到下标记为1到n,列从左到右标记为1到m。处于第r行第c列的格子用(r,c)表示。

刚开始的时候猪站在(1,1),他的目标是走到(n,m)。由于猪回家心切,他在(r,c)的时候,只会往(r+1,c)或(r,c+1)走。他不能走出这个森林。

这只猪所在的森林是一个非同寻常的森林。有一些格子看起来非常相似,而有一些相差非常巨大。猪在行走的过程中喜欢拍下他经过的每一个格子的照片。一条路径被认为是漂亮的当且仅当拍下来的照片序列顺着看和反着看是一样的。也就是说,猪经过的路径要构成一个回文。

数一数从(1,1)到(n,m)有多少条漂亮路径。答案可能非常巨大,请输出对 109+7 取余后的结果。

样例解释:有三种可能

  


Input
单组测试数据。
第一行有两个整数 n,m (1≤n,m≤500),表示森林的长和宽。
接下来有n行,每行有m个小写字母,表示每一个格子的类型。同一种类型用同一个字母表示,不同的类型用不同的字母表示。
Output
输出答案占一行。
Input示例
3 4
aaab
baaa
abba
Output示例
3
System Message  (题目提供者)
Visual C++的运行时限为:2000 ms ,空间限制为:131072 KB  示例及语言说明请按这里

 允许其他 AC 的用户查看此代码,分享代码才能查看别人的代码并有机会获得勋章

一开始觉得很难搞,因为光方案数就有很多种,然后还要从中找出回文路径,觉得无从下手。

后来看了发题解,发现可以多线程搞搞,瞬间顿悟了。(好久没写多线程DP了。)

首先定义5维DP是不现实的。一个很容易想到的是三维的dp、

dp[i][j][k]:表示从起点出发的点走到(i,j)和从终点出发的点走到(k,t)的满足题意的方案数,t我们可以公式求出。

但是500*500*500还是不行的,因此只能考虑用滚动数组了。我们可以参考机器人走方格。

当前和一定只和当前行或者前一行推得。。。。剩下的就是求递推式了。

四种情况:

dp[i % 2][j][k] = (dp[i % 2][j][k] + dp[(i - 1) % 2][j][k]) % mod;
dp[i % 2][j][k] = (dp[i % 2][j][k] + dp[(i - 1) % 2][j][k + 1]) % mod;
dp[i % 2][j][k] = (dp[i % 2][j][k] + dp[i % 2][j - 1][k]) % mod;
dp[i % 2][j][k] = (dp[i % 2][j][k] + dp[i % 2][j - 1][k + 1]) % mod;

#include  
#include         
#include                
#include  
#include        
#include      
#include 
#include  
#include                
#include                
#include                
#include        
#include       
#include        
using namespace std;
typedef long long ll;
#define inf 1000000000           
#define mod 1000000007                 
#define maxn  6005    
#define PI 3.1415926  
#define lowbit(x) (x&-x)     
#define eps 1e-9
ll dp[2][505][505];
char s[505][505];
int judge(int x, int y, int xx, int yy)
{
	if (x == xx && y == yy)
		return 1;
	if (x + 1 == xx && y == yy)
		return 1;
	if (x == xx && y + 1 == yy)
		return 1;
	return 0;
}
int main(void)
{
	ll ans = 0;
	int n, m, i, j, k, t1, t2;
	scanf("%d%d", &n, &m);
	for (i = 1;i <= n;i++)
		for (j = 1;j <= m;j++)
			scanf(" %c", &s[i][j]);
	if (s[1][1] == s[n][m])
		dp[1][1][n] = 1;
	for (i = 1;i <= n;i++)
	{
		for (j = 1;(i + j - 1) <= (n + m) / 2;j++)
			for (k = n;k >= n - (i + j - 1) + 1 && k >= 1;k--)
				if (s[i][j] == s[k][n + m - k - i - j + 2])
				{
					dp[i % 2][j][k] = (dp[i % 2][j][k] + dp[(i - 1) % 2][j][k]) % mod;
					dp[i % 2][j][k] = (dp[i % 2][j][k] + dp[(i - 1) % 2][j][k + 1]) % mod;
					dp[i % 2][j][k] = (dp[i % 2][j][k] + dp[i % 2][j - 1][k]) % mod;
					dp[i % 2][j][k] = (dp[i % 2][j][k] + dp[i % 2][j - 1][k + 1]) % mod;
					if (judge(i, j, k, n + m - i - j - k + 2))
						ans = (ans + dp[i % 2][j][k]) % mod;
				}
		memset(dp[(i - 1) % 2], 0, sizeof(dp[(i - 1) % 2]));
	}
	printf("%lld\n", ans);
	return 0;
}


你可能感兴趣的:(DP)