CodeForces - 570E(dp------------- Codeforces Round #316 (Div. 2)E

题目:给出一个字母矩阵,问从左上角走到右下角的走法有多少种走法能走出回文子串,只能向下或向右走。

思路:正解是O(n^3)的dp,也跑了2.9s,可见这题时限是比较紧的。自然的一个想法是两头同时向中间走,这样可以保证走出的是回文串,问题在于如何dp。一共需要走O(n+m)步,而每一步从左上走过来的和右下走过来的进行匹配,以行数作为下标表示二者即可(因为距离确定的情况下只需要知道一个坐标)。所以dp[i][j][k]就表示在第i步,第j行和第k行配对组成的回文串的数目,滚动数组优化空间把步数那一维去掉。转移的时候需要考虑四种走法(对应两头的两种走法相乘)。然后就是递推到中间之后,根据x和y轴的长度之和还需要稍微讨论一下。

#include <bits/stdc++.h>
#define pb push_back
#define se second
#define fs first
#define sq(x) (x)*(x)
#define eps 0.000000001
using namespace std;
typedef long long ll;
typedef pair<ll,ll> P;
const ll mod=1e9+7;
const int maxv=505;
ll dp[2][maxv][maxv];
int n,m;
char r[maxv];
char mp[maxv][maxv];
const int d1[2]={1,0};
const int d2[2]={0,1};
const int p1[2]={-1,0};
const int p2[2]={0,-1};
bool out(int x,int y){
    return x<0||x>=n||y<0||y>=m;
}
int main(){
//    freopen("/home/files/CppFiles/in","r",stdin);
    cin>>n>>m;
    for(int i=0;i<n;i++){
        scanf("%s",r);
        for(int j=0;j<m;j++){
            mp[i][j]=r[j];
        }
    }
    if(mp[0][0]!=mp[n-1][m-1]){
        cout<<0<<endl;
        return 0;
    }
    bool f=1;
    dp[0][0][n-1]=1;
    bool bbb=1;
    for(int d=0;d<(n+m-2)/2;d++){
        f^=1;
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                dp[f^1][i][j]=0;
            }
        }
        for(int i=0;i<n;i++){///up
            for(int j=0;j<n;j++){///down
                int x1=i,y1=d-x1;
                int x2=j,y2=n+m-2-d-x2;
                if(out(x1,y1)||out(x2,y2))  continue;
                for(int p=0;p<2;p++){
                    for(int q=0;q<2;q++){
                        int dx1=x1+d1[p],dy1=y1+d2[p];
                        int dx2=x2+p1[q],dy2=y2+p2[q];
                        if(out(dx1,dy1)||out(dx2,dy2)) continue;
                        if(mp[dx1][dy1]==mp[dx2][dy2]){
                            dp[f^1][dx1][dx2]=(dp[f^1][dx1][dx2]+dp[f][x1][x2])%mod;
                        }
                    }
                }
            }
        }
        ll ans=0;
        for(int i=0;i<n;i++){
            if(i+1<n&&(n+m)%2==1)
                ans=(ans+dp[f^1][i][i+1])%mod;
            ans=(ans+dp[f^1][i][i])%mod;
        }
        cout<<ans<<endl;
        return 0;
    }
}
View Code

 

posted @ 2015-08-14 16:41  PlusSeven  阅读(208)  评论(0编辑  收藏  举报