我承认这题有点水……但从我个人的角度来讲,价值很高
Description
一只猪走进了一个森林。很凑巧的是,这个森林的形状是长方形的,有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 取余后的结果。
样例解释:有三种可能
1≤n,m≤500
Solution
这道题思路清奇,才特意拿出来
明眼人都知道是DP 类似某道对角线分割的题目 我一开始也考虑了以对角线为状态
可是,按普通的单条对角线来讲 状态太大了 因为要考虑回文的限制
还好身旁经过一位大佬 他说
两条扫描线喽~
考虑设两端分别到达 (x1,y1),(x2,y2)
那么有状态 Fx1,x2,t(其中t表示步数)
显然,两坐标可以简单推出
DP本身则相对简单 不再赘述
Code
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define oo 2139062143
#define sqr(x) ((x)*(x))
#define lowbit(x) ((x)&(-x))
#define abs(x) (((x)>=0)?(x):(-(x)))
#define max(x,y) (((x)>(y))?(x):(y))
#define min(x,y) (((x)<(y))?(x):(y))
#define fo(i,x,y) for (ll i = (x);i <= (y);++ i)
#define fd(i,x,y) for (ll i = (x);i >= (y);-- i)
using namespace std;
typedef double db;
typedef long long ll;
const ll N = 550,Mo = 1e9 + 7;
ll f[2][N][N];
char ch[N][N];
ll n,m,o;
ll ans;
bool judge(ll x1,ll y1,ll x2,ll y2)
{
if ((x1 == x2 && y1 == y2) || (x1 + 1 == x2 && y1 == y2) || (x1 == x2 && y1 + 1 == y2)) return 1;
else return 0;
}
int main()
{
scanf("%lld%lld", &n, &m);
fo(i,1,n) scanf("%s", ch[i] + 1);
if (ch[1][1] == ch[n][m]) f[1][1][n] = 1;
o = 1;
fo(i,1,n)
{
fo(j,1,(n + m + 2 - 2 * i) / 2) fd(k,n,max(1,n - i - j + 2))
{
ll tmp = n + m - k - i - j + 2;
if (ch[i][j] == ch[k][tmp])
{
f[o][j][k] += f[1 - o][j][k] + f[1 - o][j][k + 1] + f[o][j-1][k] + f[o][j-1][k+1];
if (f[o][j][k] >= Mo) f[o][j][k] %= Mo;
if (judge(i,j,k,tmp))
{
ans += f[o][j][k];
if (ans >= Mo) ans %= Mo;
}
}
}
o = 1 - o;
memset(f[o],0,sizeof f[o]);
}
printf("%lld\n",ans);
}