Codeforces 570E Pig and Palindromes dp

82 篇文章 0 订阅

链接

题解链接:点击打开链接

题意:

给定n*m的字母矩阵。

从左上角到右下角的路径中有多少条是回文。

思路:

显然是要从头尾同时dp的,路径1是从左上角到第j行,路径2是从右下角到第k行

dp[i][j][k] 表示路径长度为i,路径1从左上角到第j行,路径2从右下角到第k行,且路径1和2是匹配的方法数。

对于路径1、2合并时要分一下奇偶。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <stdio.h>  
#include <iostream>  
#include <algorithm>  
#include <sstream>  
#include <stdlib.h>  
#include <string.h>  
#include <limits.h>  
#include <vector>  
#include <string>  
#include <time.h>  
#include <math.h>  
#include <iomanip>  
#include <queue>  
#include <stack>  
#include <set>  
#include <map>  
const int inf = 1e9;
const double eps = 1e-8;
const double pi = acos(-1.0);
template <class T>
inline bool rd(T &ret) {
	char c; int sgn;
	if (c = getchar(), c == EOF) return 0;
	while (c != '-' && (c<'0' || c>'9')) c = getchar();
	sgn = (c == '-') ? -1 : 1;
	ret = (c == '-') ? 0 : (c - '0');
	while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');
	ret *= sgn;
	return 1;
}
template <class T>
inline void pt(T x) {
	if (x < 0) { putchar('-'); x = -x; }
	if (x > 9) pt(x / 10);
	putchar(x % 10 + '0');
}
using namespace std;
const int N = 520;
const int mod = 1e9 + 7;
typedef long long ll;
typedef pair<int, int> pii;
void add(int &x, int y) {
	x += y;
	if (x >= mod)x -= mod;
}
int mul(int x, int y) {
	x = (ll)x*y%mod;
	return x;
}
int n, m;
char s[N][N];
vector<pii>G[1005];
int step[4][2] = { 0, 1, 1, 0, 0, -1, -1, 0 }, dis[N][N];
bool inmap(int x, int y) {
	return 1 <= x&&x <= n && 1 <= y&&y <= m;
}
void bfs() {
	queue<int>qx, qy;
	qx.push(1); qy.push(1);
	dis[1][1] = 1;
	while (!qx.empty()) {
		int ux = qx.front(), uy = qy.front();
		G[dis[ux][uy]].push_back({ ux, uy });
		qx.pop(); qy.pop();
		for (int i = 0; i < 2; i++) {
			int vx = ux + step[i][0], vy = uy + step[i][1];
			if (inmap(vx, vy) && !dis[vx][vy]) {
				dis[vx][vy] = dis[ux][uy] + 1;
				qx.push(vx); qy.push(vy);
			}
		}
	}
}
int dp[2][N][N];
int main() {
	rd(n); rd(m);
	for (int i = 1; i <= n; i++) scanf("%s", s[i] + 1);
	if (s[1][1] != s[n][m]) { puts("0"); return 0; }
	s[0][1] = 'a'; s[1][0] = 'z' + 1;
	s[n + 1][m] = 'a'; s[n][m + 1] = 'z' + 1;
	bfs();
	int cur = 0, old = 1;
	memset(dp[cur], 0, sizeof dp[cur]);
	dp[cur][1][n] = 1;
	int l = 1, r = n + m - 1;
	for (int i = 2; i <= (n + m) / 2; i++, l++, r--)
	{
		swap(cur, old);
		memset(dp[cur], 0, sizeof dp[cur]);
		for (auto u : G[l])
		{
			int x = u.first, y = u.second;
			for (auto v : G[r])
			{
				int tx = v.first, ty = v.second;
				if (dp[old][x][tx] == 0)continue;
				for (int a = 0; a < 2; a++)
				{
					int ux = x + step[a][0], uy = y + step[a][1];
					if (!inmap(ux, uy))continue;
					for (int b = 2; b < 4; b++)
					{
						int vx = tx + step[b][0], vy = ty + step[b][1];
						if (!inmap(vx, vy))continue;
						if (s[ux][uy] != s[vx][vy])continue;

						add(dp[cur][ux][vx], dp[old][x][tx]);
					}
				}
			}
		}
	}
	int ans = 0;
	if ((n + m) & 1)
	{
		for (int i = 1; i <= n; i++)
			add(ans, dp[cur][i][i]);
		for (int i = 1; i <= n; i++)
			add(ans, dp[cur][i][i + 1]);
	}
	else {
		for (int i = 1; i <= n; i++)
			add(ans, dp[cur][i][i]);
	}
	pt(ans);
	return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值