Codeforces Round #316 (Div. 2) E dp



链接:戳这里


E. Pig and Palindromes
time limit per test4 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
Peppa the Pig was walking and walked into the forest. What a strange coincidence! The forest has the shape of a rectangle, consisting of n rows and m columns. We enumerate the rows of the rectangle from top to bottom with numbers from 1 to n, and the columns — from left to right with numbers from 1 to m. Let's denote the cell at the intersection of the r-th row and the c-th column as (r, c).

Initially the pig stands in cell (1, 1), and in the end she wants to be in cell (n, m). Since the pig is in a hurry to get home, she can go from cell (r, c), only to either cell (r + 1, c) or (r, c + 1). She cannot leave the forest.

The forest, where the pig is, is very unusual. Some cells of the forest similar to each other, and some look very different. Peppa enjoys taking pictures and at every step she takes a picture of the cell where she is now. The path through the forest is considered to be beautiful if photographs taken on her way, can be viewed in both forward and in reverse order, showing the same sequence of photos. More formally, the line formed by the cells in order of visiting should be a palindrome (you can read a formal definition of a palindrome in the previous problem).

Count the number of beautiful paths from cell (1, 1) to cell (n, m). Since this number can be very large, determine the remainder after dividing it by 109 + 7.

Input
The first line contains two integers n, m (1 ≤ n, m ≤ 500) — the height and width of the field.

Each of the following n lines contains m lowercase English letters identifying the types of cells of the forest. Identical cells are represented by identical letters, different cells are represented by different letters.

Output
Print a single integer — the number of beautiful paths modulo 109 + 7.

Examples
input
3 4
aaab
baaa
abba
output
3
Note
Picture illustrating possibilities for the sample test.


题意:

给出n*m的矩阵的字符,问从(1,1)走到(n,m)走过的字符是回文串的方案数(每次只能往下或右)


思路:

(1,1)右或下 和 (n,m)左或上 同时开始走,所有走的长度是一样的,那么直接判断当前的s[x1][y1]?==s[x2][y2]

设置dp状态:dp[len][x1][y1][x2][y2]

表示当前走的路程长度为len,(1,1)走到了点(x1,y1) (n,m)走到了点(x2,y2) 的方案数

然后转移方程也就是(x1,y1)从两个方向过来,(x2,y2)两个方向过来,总共四种情况

但是这里会超空间,可以发现y1,y2都是可以同x1,x2得到的,所以dp方程变成dp[len][x1][x2]

但是还是会超,注意这里的长度为len只与len-1有关,所以用滚动数组变成dp[2][x1][x2]

具体看代码


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include <ctime>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<iomanip>
#include<cmath>
#define mst(ss,b) memset((ss),(b),sizeof(ss))
#define maxn 0x3f3f3f3f
#define MAX 1000100
///#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
typedef unsigned long long ull;
#define INF (1ll<<60)-1
using namespace std;
#define mod 1000000007
int dp[2][550][550];
char s[550][550];
int n,m;
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%s",s[i]+1);
    if(s[1][1]==s[n][m]) dp[0][1][n]=1;
    else dp[0][1][n]=0;
    int now=0,last=1;
    int len=(n+m-2)/2;
    for(int i=1;i<=len;i++){
        swap(now,last);
        mst(dp[now],0);
        for(int x1=1;x1<=i+1;x1++){
            for(int x2=n;x2>=n-i;x2--){
                int y1=i-x1+2;
                int y2=n+m-x2-i;
                if(x1>x2 || y1>y2) continue;
                if(s[x1][y1]==s[x2][y2]){
                    dp[now][x1][x2]=(dp[now][x1][x2]+dp[last][x1][x2])%mod;///(x1,y1-1)(x2,y2+1)
                    dp[now][x1][x2]=(dp[now][x1][x2]+dp[last][x1-1][x2])%mod;///(x1-1,y1)(x2,y2+1)
                    dp[now][x1][x2]=(dp[now][x1][x2]+dp[last][x1][x2+1])%mod;///(x1,y1-1)(x2+1,y2)
                    dp[now][x1][x2]=(dp[now][x1][x2]+dp[last][x1-1][x2+1])%mod;///(x1-1,y1)(x2+1,y2)
                }
            }
        }
    }
    int ans=0;
    for(int i=1;i<=n;i++)
        ans=(ans+dp[now][i][i])%mod;
    if((n+m)%2==1){
        for(int i=1;i<n;i++){
            ans=(ans+dp[now][i][i+1])%mod;
        }
    }
    cout<<ans<<endl;
    return 0;
}


(1,1)右或下和(n,m)同时开始走,
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值