Codeforces #316 E Pig and Palindromes DP

//	Codeforces #316 E Pig and Palindromes
//
//	题目大意:
//
//		给你一张地图,n*m每个点是一个字母,现在从(0,0)出发,
//	每次只能往右或者往下走,求走到(n-1,m-1)形成回文串的方法数.
//
//	解题思路:
//
//		动态规划.首先.如果起点和终点的字母不相同,那么肯定
//	不能形成回文串,直接输出0.对于能形成回文串.我们设状态
//	d(step,i,j)表示走了step步,从第0行走到i行,第n-1行走到j行的
//	能形成回文串的方法数.
//	1)从左上方只能往右,或者下方走
//	2)从右下方只能往左,或者上方走
//	我们采用刷表法从d(step,i,j)分别对
//
//	d(step+1,i+1,j) 下,左
//	d(step+1,i+1,j-1) 下,上
//	d(step+1,i,j); 右,左
//	d(step+1,i,j-1); 右,上
//
//	由于内存的限制,而状态只依赖于上一步的状态.则我们只需要step开2维即可
//	或者用一个temp数组暂时存储.
//
//	最后的结果也要分所形成的回文串的奇偶来判断.
//
//	回文串奇数:
//
//		这样一定是到了一个共同的字母,即中间的字母就相遇了.即走到了同一行
//	累加d(i,i).输出结果.
//
//	回文串偶数:
//
//		这样最后一定是双方同时走一步正好相邻.换而言之相遇的结果只能是左上方
//	走到某个点x(i,j),同时右下方的点走到了x的右边一个或者下边一个.这时候判断
//	并做累加就好了.
//
//	感悟:
//
//		这道题,虽然题目的意思很简单,但是对于我看来,实在是太复杂了,哎,dp的弱才啊
//	我开始看的是红名爷的代码,有很多疑惑的地方,最后MY一眼看出就是SB题目,给我讲了
//	状态,转移.还有边界等一系列.可以说是手把手的教.哎,卡了这么久,总算是能够真正
//	的理解红名爷还有MY的思路了.差距就是这么大啊,小子在此感谢MY还有红名爷~~~
//	哎,不说什么了,继续加油吧!FIGHTING

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long ll;
const ll MOD = 1e9 + 7;
const int maxn = 508;
char g[maxn][maxn];

ll d[maxn][maxn];
ll tmp[maxn][maxn];
int n,m;

bool ok(int x1,int y1,int x2,int y2){
	if (x1<n && y1<m && x2>=0 && y2>=0 && g[x1][y1] == g[x2][y2])
		return true;
	return false;
}

void add(ll &x ,ll y){
	x += y;
	if (x>=MOD)
		x -= MOD;
}

void print(){
	for (int i=0;i<n;i++){
		for (int j=0;j<m;j++)
			cout << d[i][j] << " ";
		cout << endl;
	}
}

void input(){
	for (int i=0;i<n;i++)
		scanf("%s",g[i]);
	if (g[0][0]!=g[n-1][m-1]){
		puts("0");
		return ;
	}

	memset(d,0,sizeof(d));
	memset(tmp,0,sizeof(tmp));

	d[0][n-1] = 1;

	int s = n + m - 2;

	for (int step = 0; step < s/2;step++){
		for (int x0 = 0;x0 < n && step - x0 >=0;x0++){
			int y0 = step - x0;
			for (int x1 = 0;x1 < n && s - step - x1>=0 ;x1++){

				int y1 = s - step - x1;

				if (ok(x0+1,y0,x1-1,y1)){
					add(tmp[x0+1][x1-1],d[x0][x1]);
				}
				if (ok(x0+1,y0,x1,y1-1)){
					add(tmp[x0+1][x1],d[x0][x1]);
				}
				if (ok(x0,y0+1,x1-1,y1)){
					add(tmp[x0][x1-1],d[x0][x1]);
				}
				if (ok(x0,y0+1,x1,y1-1)){
					add(tmp[x0][x1],d[x0][x1]);
				}
			}
		}
		for (int i=0;i<n;i++)
			for (int j=0;j<n;j++){
				d[i][j] = tmp[i][j];
				tmp[i][j] = 0;
			}
	}
	if (n + m - 1 & 1){
		ll ans = 0;
		for (int i=0;i<n;i++){
			add(ans,d[i][i]);
		}
		printf("%I64d\n",ans);
	}else {
		ll ans = 0;
		s /= 2;
		for (int i=0;i<n;i++){ // i表示走到了i行
			if (s - i + 1 < m && g[i][s-i]==g[i][s-i+1]) //判断走到该点的右边是否与之相同
				add(ans,d[i][i]);
			if (i + 1 < n && g[i][s-i] == g[i+1][s-i]) // 判断走到该点的下边是否与之相同
				add(ans,d[i][i+1]);
		}
		printf("%I64d\n",ans);
	}

}

int main(){
	//freopen("1.txt","r",stdin);
	while(scanf("%d%d",&n,&m)!=EOF){
		input();
	}
	return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-20 22:27:37

Codeforces #316 E Pig and Palindromes DP的相关文章

codeforces 570 E. Pig and Palindromes (DP)

题目链接: 570 E. Pig and Palindromes 题目描述: 有一个n*m的矩阵,每个小格子里面都有一个字母.Peppa the Pig想要从(1,1)到(n, m).因为Peppa the Pig是一个完美主义者,她想要她所经过的路径上的字母组成的字符串是一个回文串,现在Peppa the Pig想要知道有多少满足条件的走法? 解题思路: 因为经过路径上的字母要组成回文串,所以可以从(1,1),(n,m)同时开始dp.从(1,1)出发只能向下方和右方走,从(n,m)出发只能向上

Codeforces Round #316 (Div. 2)E. Pig and Palindromes DP

E. Pig and Palindromes Peppa the Pig was walking and walked into the forest. What a strange coincidence! The forest has the shape of a rectangle, consisting of n rows and m columns. We enumerate the rows of the rectangle from top to bottom with numbe

Codeforces 570E Pig and Palindromes dp

链接 题解链接:点击打开链接 题意: 给定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 <std

codeforces 570 E. Pig and Palindromes

题意:给出n*m的字母表,求从左上角走到右下角能形成多少个回文串,只能往下或往右走. 做法:dp[r1][c1][r2][c2],从左上角走到(r1,c1),从右下角走到(r2,c2)时,能形成多少个回文串,因为爆内存,表示成dp[step][r1][r2],从左上角走到r1行,从右下角走到r2行,分别走了step步时,能形成多少个回文串,因为c1=step+2-r1,c2=n+m-step-r2,所以是一样的,这样差不多能过了,因为两边最多走250步,所以需要的空间是250*500*500,当

CF 316div2 E.Pig and Palindromes

E. Pig and Palindromes Peppa the Pig was walking and walked into the forest. What a strange coincidence! The forest has the shape of a rectangle, consisting of n rows and m columns. We enumerate the rows of the rectangle from top to bottom with numbe

CodeForces 540D Bad Luck Island 概率dp

CodeForces 540D 应该是简单概率dp,由于写得少显得十分蠢萌 求期望逆推,求概率正推,大概是这么个意思,贴一发留恋 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define db double const int maxn=108; db dp[maxn][maxn][maxn]; int main() { int i,j,n,m,k,p; whi

codeforces 148E Aragorn&#39;s Story 背包DP

Aragorn's Story Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://codeforces.com/problemset/problem/148/E Description Our protagonist is the handsome human prince Aragorn comes from The Lord of the Rings. One day Aragorn finds a lot of enemies who

CodeForces 21D Traveling Graph 状压dp+欧拉回路

题目链接:点击打开链接 题意: 给定n个点m条边的无向图 求从1点开始经过每条边至少一次最后回到1点的最小路程 显然就是找一条路径可重复的欧拉回路 思路: 首先对于欧拉回路的结论是:所有点的度数都为偶数 因为所有边至少经过一次,那么可以把题意转换成加最少多少条边使得图满足以上结论 而加的边目的是为了把奇度数转成偶度数,先floyd一下得到任意点间加边的最小花费 dp[i]表示状态i下度数都为偶数的最小花费. 状压dp,把i状态下,所有未选择的点中挑2个奇度数的转移即可. #include <cs

Codeforces 67C Sequence of Balls 编辑距离 dp

题目链接:点击打开链接 有一个交换操作比较特殊,所以记录每个点距离自己最近的那个字符的位置 然后交换就相当于把第一行要交换的2个字符 之间的字符都删掉 把第二行要交换的2个字符 之间的字符都插入第一行的2个字符之间 然后再进行交换. #include <cstdio> #include <cstring> #include<iostream> using namespace std; #define inf 10000000 #define N 4005 #define