我承認這題有點水……但從我個人的角度來講,價值很高
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 取餘後的結果。
樣例解釋:有三種可能
Solution
這道題思路清奇,才特意拿出來
明眼人都知道是DP 類似某道對角線分割的題目 我一開始也考慮了以對角線爲狀態
可是,按普通的單條對角線來講 狀態太大了 因爲要考慮迴文的限制
還好身旁經過一位大佬 他說
兩條掃描線嘍~
考慮設兩端分別到達
那麼有狀態
顯然,兩座標可以簡單推出
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);
}