1. 程式人生 > >CF 316div2 E.Pig and Palindromes

CF 316div2 E.Pig and Palindromes

pen reverse mes lin represent sample eno n) number

E. Pig and Palindromes

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.

Sample test(s)

input
3 4
aaab
baaa
abba
output
3

題意概述:在一個n*m的矩陣中,每個格子都有一個字母。你從(1,1)出發前往(n,m),每次僅僅能向下或向右。當到達終點時,把你經過的字母寫下來。產生一個字符串。求有多少種走成回文的方案。

每一次僅僅能向下或向右。所以考慮能夠用dp做。考慮曼哈頓距離
按距離原點和終點的曼哈頓距離同樣的兩個點做狀態轉移
想象有兩個點分別從起點和終點同一時候向中間走
用f[p1][p2] 表示 第一個點在p1位置第二個點在p2位置時的從起點終點同一時候走過的同樣字母路徑的合法狀態數

f[p1][p2]=f[p1_f1][p2_f1]+f[p1_f1][p2_f2]+f[p1_f2][p2_f1]+f[p1_f2][p2_f2]

p1_f1,p1_f2,p2_f1,p2_f2分別表示p1和p2的前驅點

因為坐標非常大,須要用滾動數組優化。斜著循環每個點也須要一些小技巧詳細看代碼~

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
using namespace std;
const int MAX=505;
const int MOD=1e9+7;
char s[MAX][MAX];
int f[MAX][MAX]={0};
int f_[MAX][MAX];
int i,j,m,n,k,dis;
struct point{
    int x,y;
};
point next_1(point a)
{
    if (a.y==1&&a.x<n)
        a.x++;
    else
        a.y++;
    return a;
}
point next_2(point a)
{
    if (a.x==n&&a.y>1)
        a.y--;
    else
        a.x--;
    return a;
}
point nex(point a)
{
    a.x--;
    a.y++;
    return a;
}
int main()
{
    cin>>n>>m;
    int ans=0;
    getchar();
    for (i=1;i<=n;i++)
    {
        for (j=1;j<=m;j++)
            scanf("%c",&s[i][j]);
        getchar();
    }
    point a,b,p1,p2;
    a.x=a.y=1;
    b.x=n;b.y=m;
    int max_=(m+n)/2;
    if (s[1][1]==s[n][m])
        f[1][n]=1;
    else
        f[1][n]=0;
    if (m+n<=3)
    {
        cout<<f[1][n]<<endl;
        return 0;
    }
    for (dis=2;dis<=max_;dis++)
    {
        a=next_1(a);
        b=next_2(b);
        for (i=1;i<=500;i++)
            for (j=1;j<=500;j++)
            {
                f_[i][j]=f[i][j];
                f[i][j]=0;
            }
        for (p1=a;p1.y<=m&&p1.x>=1;p1=nex(p1))
            for (p2=b;p2.y<=m&&p2.x>=1;p2=nex(p2))
                if (s[p1.x][p1.y]==s[p2.x][p2.y])
                {
                    f[p1.x][p2.x]=((f_[p1.x-1][p2.x]+f_[p1.x-1][p2.x+1])%MOD+(f_[p1.x][p2.x]+f_[p1.x][p2.x+1])%MOD)%MOD;
                    if (((p1.x==p2.x)&&(abs(p1.y-p2.y)<=1))||((p1.y==p2.y)&&(abs(p1.x-p2.x)<=1)))
                        ans=(ans+f[p1.x][p2.x])%MOD;
                }
    }
    cout<<ans<<endl;
    return 0;
}

貼一個cf上看到的位運算的程序,相當簡短

#include <bits/stdc++.h>
using namespace std;
#define f(i,n) for(int i=0;i<(n);i++)
#define fr(i,n) for(int i=n;i--;)
char x[500][501];
int d[2][501][501],n,m;
main(){
    cin>>n>>m;
    f(i,n) cin>>x[i];
    f(ei,n) fr(si,n) fr(sj,m){
        auto& c=d[ei&1][si][sj]=0,ej=n+m-2-si-sj-ei;
        if(si<=ei&&sj<=ej&&x[si][sj]==x[ei][ej]&&!(c=abs(si-ei)+abs(sj-ej)<=1))
            f(i,2) f(j,2) c=(c+d[ei-!j&1][si+!i][sj+!!i])%((int)1e9+7);
    }
    cout<<d[~n&1][0][0]<<‘\n‘;
}

CF 316div2 E.Pig and Palindromes