寻宝之后(rms模拟5-2)* * *(dp)

题目描述
迷宫是一个 n*m的字符矩阵。 小明在这个矩阵的左上角,只能向下和向右走,去和在矩阵右下角的小芳会合。 小明必须将他走过的路径上的,经过的字符收集起来。如果到右下角时他收集到的这些
字符连在一起是回文的,那么他就能够走出这个迷宫,否则他就会掉进陷阱出不来。 小明想知道有多少条路径能够让他走出这个迷宫。由于答案可能很大,请对 1000000007取模。
输入格式
第一行两个整数 n 和m。 接下来 n 行,每行m个字符表示这个矩阵
输出格式
输出一行一个整数表示答案
输入样例#1
3 4
aaab
baaa
abba
输出样例#1
3
数据范围
对于 20%的数据,满足 n∗m≤10 对于另外 10%的数据,满足字符都是 a 对于 70%的数据,满足 n,m≤60
对于 100%的数据,满足 n,m≤500

题解
dp
d[step][x1][x2]记录第step步从(0,0)走到(x1,y1) 且从(n-1,m-1)走到(x2,y2)的方法数
y可用step与x表示
d可用滚动数组优化

代码

#include<bits/stdc++.h>
#define F( i,a,b ) for( int i=(a);i<=(b);i++ )
#define F_2( i,a,b ) for( int i=(a);i>=(b);i-- )
#define N 507
#define M 10001
#define P 1000000007
#define LL long long
#define oo 0x7fffffff
using namespace std;

inline int read()
{
    int f=1,s=0;
    char ch=getchar();
    while( ch>'9' || ch<'0' ) { if( ch=='-' ) f=-1; ch=getchar(); }
    while( ch<='9' && ch>='0' ) { s=( s<<1 )+( s<<3 )+ch-'0'; ch=getchar(); }
    return f*s;
}

const int dx[N]={ 0,1,0,-1,0 };
const int dy[N]={ 0,0,1,0,-1 };

int m,n,k;
int tot,ans,cnt,lab;
string a[N];
int d[2][N][N];

void dp()
{
    d[lab][0][n-1]=1;
    F( step,1,(m+n-2)/2 ) 
    {
        lab^=1;
        int mini=min( n-1,step );
        memset( d[lab],0,sizeof( d[lab] ) );
        F( i,0,mini )
        {
            int maxj=max( 0,n-1-step );
            F_2( j,n-1,maxj )
            {
                if( a[i][step-i]==a[j][m+n-2-step-j] )
                {
                    d[lab][i][j]=( d[lab][i][j]+d[lab^1][i][j] )%P;
                    d[lab][i][j]=( d[lab][i][j]+d[lab^1][i][j+1] )%P;
                    if( i-1>=0 )
                    {
                        d[lab][i][j]=( d[lab][i][j]+d[lab^1][i-1][j] )%P;
                        d[lab][i][j]=( d[lab][i][j]+d[lab^1][i-1][j+1] )%P;
                    }
                }
            }
        }
    } 
} 

int main()
{
    freopen( "treasure.in","r",stdin );
    freopen( "treasure.out","w",stdout );
    n=read();
    m=read();
    F( i,0,n-1 )
        cin>>a[i];
    dp();
    int len=( m+n-2)/2;
    len=min( len,n-1 );
    F( i,0,n-1 )
        ans=( ans+d[lab][i][i] )%P;
    if( (n+m)%2 )
        F( i,0,n-1 ) 
            ans=( ans+d[lab][i][i+1] )%P;
    cout<<ans<<endl; 
    return 0;
}








  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值