1. 程式人生 > >Codeforces 570E Pig and Palindromes : DP+滾動

Codeforces 570E Pig and Palindromes : DP+滾動

最近在泛刷CF,感覺這種題……反正就很眼熟。好吧其實我是看到Palindrome就決定做他了……

題意:

給出一個n*m(n,m<=500)的矩形區域,每個格子上有一個小寫字母,從(0,0)出發,只能向右或上走,走到(n,m),且要求路徑上的字元構成迴文串,問方案數。

題解:

由於是迴文串,要求對稱,因此我們從兩頭一起走。
dp[step][xl][xr]dp[step][xl][xr]表示現在兩頭分別走到了(xl,stepxl)(xl,step-xl)點,以及(xr,n+m2stepxr)(xr,n+m-2-step-xr)

,n+m2stepxr)點的方案數。考慮左下角的點只可能由左邊/下邊的點轉移而來,同理右上角的點只能由右邊/上邊的點轉移而來,因此轉移複雜度為O(4)O(4),整體複雜度是O(4nm(n+m2)/2)=O(4n3)O(4*n*m*(n+m-2)/2)=O(4n^3)
最後再分奇偶來組合以下答案就可以了。

同時,陣列第一維要滾動,否則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; }