CF 316 E. Pig and Palindromes 求左上角走到右下角是回文的方法数 DP

来源:互联网 发布:大数据培训好就业吗 编辑:程序博客网 时间:2024/06/02 01:17

题意:给一个n*m的格子,每个格子有一个字母,只有向下和向左两种走法,现在要求,从左上角走到右下角,走过的格子的字母是回文的有多少种走法?

DP,枚举步数,因为是回文串,所以应该是对称的,步数应该为(n+m)2向下取整,可以知道,以左上角为起点走,走step步,走到的点是固定的,假设从左上角走到(r1,c1)这个点,并且走了step步,那么明显有r1+c1=step+1(由(1,1)走到(r1,c1)),从右下角走到(r2,c2)这个点,并且走了step步,那么明显有r2+c2=n+m+1step(由(n,m)走到(r2,c2)),那么对于每一个c1c2都直接用公式算出对应的r1r2,对于每一个step,枚举(c1,r1)(c2,r2),第step步由step+1递推而来。。可以用滚动数组节约空间。
代码:

//author: CHC//First Edit Time:  2015-08-29 15:06#include <iostream>#include <cstdio>#include <cstring>#include <cmath>#include <set>#include <vector>#include <map>#include <queue>#include <set>#include <algorithm>#include <limits>using namespace std;typedef long long LL;const int MAXN=510;const int INF = numeric_limits<int>::max();const LL LL_INF= numeric_limits<LL>::max();const int mod=1e+9 + 7;LL dp[2][MAXN][MAXN];int n,m;char mapp[MAXN][MAXN];bool check(int x){    return x>=1&&x<=n;}int main(){    while(~scanf("%d%d",&n,&m)){        for(int i=1;i<=n;i++)            scanf(" %s",mapp[i]+1);        int k=0;        for(int step=(n+m)/2;step>0;step--){            k^=1;            for(int c1=1;c1<=m;c1++){                for(int c2=c1;c2<=m;c2++){                    int r1=step-c1+1;                    int r2=n+m-step-c2+1;                    if(!(check(r1)&&check(r2)&&r1<=r2))continue;                    //printf("step:%d %d %d %d %d\n",step,r1,c1,r2,c2);                    if(mapp[r1][c1]==mapp[r2][c2]){                        if(r1==r2&&c1==c2)dp[k][c1][c2]=1;                        else if(r1==r2&&c1+1==c2)dp[k][c1][c2]=1;                        else if(r1+1==r2&&c1==c2)dp[k][c1][c2]=1;                        else                             dp[k][c1][c2]=(dp[k^1][c1+1][c2]+dp[k^1][c1+1][c2-1]+dp[k^1][c1][c2-1]+dp[k^1][c1][c2])%mod;                    }                    else dp[k][c1][c2]=0;                }            }        }        printf("%I64d\n",dp[k][1][m]%mod);    }    return 0;}
0 0