一只猪走进了一个森林。很凑巧的是,这个森林的形状是长方形的,有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#include <iostream> #include <math.h> #include <vector> #include <cstring> using namespace std; typedef long long int ll; const int SIZE = 501; const int MOD = 1e9 + 7; int dp[2][SIZE][SIZE]; char input[SIZE][SIZE]; bool isNeighbor(int x1, int y1, int x2, int y2) { if (x1 == x2 && y1 == y2) { return true; } if (x1 + 1 == x2 && y1 == y2) { return true; } if (x1 == x2 && y1 + 1 == y2) { return true; } return false; } int main(int argc, const char * argv[]) { int n, m; cin >> n >> m; memset(input, 0, sizeof(input)); for (int i = 1; i <= n; i++) { cin >> input[i]; for (int j = m; j >= 1; j--) { input[i][j] = input[i][j-1]; } } memset(dp, 0, sizeof(dp)); if (input[1][1] == input[n][m]) { dp[1][1][n] = 1; } else { cout << 0 << endl; return 0; } ll result = 0; for (int i = 1; i <= n; i++) { for (int j = 1; i+j <= (n+m+2)/2; j++) { for (int k = n; k >= i; k--) { if (input[i][j] == input[k][n+m-i-j-k+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 (isNeighbor(i, j, k, n+m-i-j-k+2)) { result = (result + dp[i%2][j][k]) % MOD; } } } } memset(dp[(i-1)%2], 0, sizeof(dp[(i-1)%2])); } cout << result << endl; return 0; }