Codeforces 570E Pig and Palindromes : DP+滾動
阿新 • • 發佈:2019-02-11
最近在泛刷CF,感覺這種題……反正就很眼熟。好吧其實我是看到Palindrome就決定做他了……
題意:
給出一個n*m(n,m<=500)的矩形區域,每個格子上有一個小寫字母,從(0,0)出發,只能向右或上走,走到(n,m),且要求路徑上的字元構成迴文串,問方案數。
題解:
由於是迴文串,要求對稱,因此我們從兩頭一起走。
表示現在兩頭分別走到了點,以及點的方案數。考慮左下角的點只可能由左邊/下邊的點轉移而來,同理右上角的點只能由右邊/上邊的點轉移而來,因此轉移複雜度為,整體複雜度是
最後再分奇偶來組合以下答案就可以了。
同時,陣列第一維要滾動,否則MLE。
Code:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long long ll;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef long double db;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int inf = 0x3f3f3f3f;
#define PB(x) push_back(x)
#define rep(i,l,r) for (ll i = l,_ = r;i< _;i++)
#define REP(i,l,r) for (ll i=l,_=r;i<=_;i++)
#define leave(x) do {cout<<#x<<endl;fflush(stdout);return 0;}while (0)
#define untie do{ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);}while (0)
/************* header ******************/
const int maxn = 5e2+10;
const ll mod = 1e9+7;
ll dp[2][maxn][maxn];
int dxl[] = {-1,0};
int dyl[] = {0,-1};
int dxr[] = {1,0};
int dyr[] = {0,1};
int n,m;
char s[maxn][maxn];
inline bool check(int x,int y){
return x>=0 && x<n && y >=0 && y<m;
}
inline void add(ll & tar,ll val){
tar = (tar + val) %mod;
}
int main(){
scanf("%d%d",&n,&m);
rep(i,0,n)scanf("%s",s+i);
if (s[0][0] != s[n-1][m-1])leave(0);
dp[0][0][n-1] = 1;
int now = 0;
int Top = (n+m-2)>>1;
for (ll step = 1;step <= Top;step++,now ^=1){
memset(dp[now^1],0,sizeof dp[0]);
REP(xl,0,min(step,1ll*n-1))REP(xr,max(0ll,n-1-step),n-1){
int yl = step - xl;
int yr = n+m-2-step - xr;
if (yl<0 || yr<0 || yl >=m || yr >=m)continue;
if (s[xl][yl] != s[xr][yr])dp[now^1][xl][xr] = 0;
else{
rep(kl,0,2)rep(kr,0,2){
int xxl = xl + dxl[kl];
int yyl = yl + dyl[kl];
int xxr = xr + dxr[kr];
int yyr = yr + dyr[kr];
if (check(xxl,yyl) && check(xxr,yyr)){
add(dp[now^1][xl][xr],dp[now][xxl][xxr]);
}
}
}
}
}
// REP(step,0,1)REP(i,0,n-1)REP(j,0,n-1){
// cout<<"dp["<<step<<"]["<<i<<"]["<<j<<"]="<<dp[step][i][j]<<endl;
// }
ll ans =0;
if ((n+m) &1){
rep(i,0,n)REP(j,i,min(1ll*n-1,i+1)){
add(ans,dp[now][i][j]);
}
}else{
rep(i,0,n){
add(ans,dp[now][i][i]);
}
}
printf("%lld\n",ans);
return 0;
}