初三奥赛模拟测试1--T1回文

初三奥赛模拟测试1--\(T1\)回文

HZOI

题意

给定一个 \(n \times m\) 的,由字符组成的矩阵 \(A\) , 问你由 \(( 1 , 1 )\) 开始,点 \(( i , j )\) 只可以往 \(( i + 1 , j )\)\(( i , j + 1 )\) 走,走到 \(( n , m )\) 停。

记录路径,问由路径上的字符构成的字符串能是回文串的走的种数 \(\bmod \ mod\) 的值 。

\(n \le 500\) , \(m \le 500\)


题解

一眼能看出来是 \(DP\) 哈,就是不知道怎么 \(DP\) 😃

考虑一下回文串有什么性质。

首先设其长度为 \(len\) , 回文串为 \(s\) , 易看出一条性质 \(0\)

\[s_{ i } = s_{ len + 1 - i } \ \ \ \ \ \ \ \ \ \ ( 1 \le i \le len ) \]

对于这个题,我们还有另外的性质:

1.无论怎么走,字符串长度是固定的。

2.设走到点 \(( i , j )\) 时,字符串达到的长度为 \(num_{ i , j }\) , 则无论如何跑, \(num_{ i , j }\) 不变。

3.对于第 \(i\) 行的第 \(j\) 个点, 他在字符串上与其距离为 \(l\) 点在第 \(k\) 行中最多匹配一个。

那么能看出其单调性了,也就是说存在构造方式使得更新过的点不再被更新。

如果不考虑第三个性质时我们的构造为:

\(dp_{ i , j , k , l }\) 表示点 \(( i , j )\) 和点 \(( k , l )\)

但我们有了性质\(3\) , 则可以构造为:

\(dp_{ i , j , k }\) 表示点 \(( i , j )\) 符合性质0 的另一个在第 \(k\) 行的点。

\(DP\) 转移方程如下:

inline void pd( int xi , int yi , int xj , int yj , int len )
{
    flag = 0 ; 
    if ( num[ xi ][ yi + 1 ] + num[ xj ][ yj - 1 ] == len && yi + 1 <= m && yj - 1 > 0 )
    {
        flag = 1 ; 
        dp[ xi ][ yi ][ xj ] = ( dp[ xi ][ yi ][ xj ] + dp[ xi ][ yi + 1 ][ xj ] ) % mod ; 
    }
    if ( num[ xi ][ yi + 1 ] + num[ xj - 1 ][ yj ] == len && yi + 1 <= m && xj - 1 > 0 )
    {
        flag = 1 ; 
        dp[ xi ][ yi ][ xj ] = ( dp[ xi ][ yi + 1 ][ xj - 1 ] + dp[ xi ][ yi ][ xj ] ) % mod ; 
    }
    if ( num[ xi + 1 ][ yi ] + num[ xj ][ yj - 1 ] == len && xi + 1 <= n && yj - 1 > 0 )
    {
        flag = 1 ; 
        dp[ xi ][ yi ][ xj ] = ( dp[ xi + 1 ][ yi ][ xj ] + dp[ xi ][ yi ][ xj ] ) % mod ; 
    }
    if ( num[ xi + 1 ][ yi ] + num[ xj - 1 ][ yj ] == len && xi + 1 <= n && xj - 1 > 0 )
    {
        flag = 1 ; 
        dp[ xi ][ yi ][ xj ] = ( dp[ xi + 1 ][ yi ][ xj - 1 ] + dp[ xi ][ yi ][ xj ] ) % mod ; 
    }
}

\(( x_i , y_i )\)\((x_j , y_j )\) 为一对满足性质 \(0\) 且点权相等的点。

\(len = n+m\)

\(code\)

点我点我
#include <bits/stdc++.h>
using namespace std ; 
const int mod = 993244853 ; 
const int N = 510 ; 
int n , m ; 
char a[ N ][ N ] ; 
struct node
{
    int x , y ;  
}pos[ N * 3 ][ N * 3 ] ; 
int num[ N ][ N ] , nump[ N * 3 ] ; 
unsigned int dp[ N ][ N ][ N ] ; 
bool flag = 0 ; 
inline int abss( int p )
{
    if ( p < 0 ) return - p ; 
    return p ; 
}
inline void pd( int xi , int yi , int xj , int yj , int len )
{
    flag = 0 ; 
    if ( num[ xi ][ yi + 1 ] + num[ xj ][ yj - 1 ] == len && yi + 1 <= m && yj - 1 > 0 )
    {
        flag = 1 ; 
        dp[ xi ][ yi ][ xj ] = ( dp[ xi ][ yi ][ xj ] + dp[ xi ][ yi + 1 ][ xj ] ) % mod ; 
    }
    if ( num[ xi ][ yi + 1 ] + num[ xj - 1 ][ yj ] == len && yi + 1 <= m && xj - 1 > 0 )
    {
        flag = 1 ; 
        dp[ xi ][ yi ][ xj ] = ( dp[ xi ][ yi + 1 ][ xj - 1 ] + dp[ xi ][ yi ][ xj ] ) % mod ; 
    }
    if ( num[ xi + 1 ][ yi ] + num[ xj ][ yj - 1 ] == len && xi + 1 <= n && yj - 1 > 0 )
    {
        flag = 1 ; 
        dp[ xi ][ yi ][ xj ] = ( dp[ xi + 1 ][ yi ][ xj ] + dp[ xi ][ yi ][ xj ] ) % mod ; 
    }
    if ( num[ xi + 1 ][ yi ] + num[ xj - 1 ][ yj ] == len && xi + 1 <= n && xj - 1 > 0 )
    {
        flag = 1 ; 
        dp[ xi ][ yi ][ xj ] = ( dp[ xi + 1 ][ yi ][ xj - 1 ] + dp[ xi ][ yi ][ xj ] ) % mod ; 
    }
    if ( flag == 1 && dp[ xi ][ yi ][ xj ] == 0 && ( n + m - 1 ) % 2 == 0 )
    {
        if ( ( xi == xj && ( abss( yi - yj ) == 1 ) || ( yi == yj && ( abss( xi - xj ) == 1 ) ) ) )
        dp[ xi ][ yi ][ xj ] = 1 ; 
    }
    dp[ xj ][ yj ][ xi ] = dp[ xi ][ yi ][ xj ] ; 
}
signed main( )
{
    ios::sync_with_stdio( 0 ) ; cin.tie( 0 ) ; cout.tie( 0 ) ; 
    cin >> n >> m ; 
    for (int i = 1 ; i <= n ; ++ i )
    {
        for ( int j = 1 ; j <= m ; ++ j )
        {
            cin >> a[ i ][ j ] ; 
            if ( num[ i - 1 ][ j ] )
            {
                num[ i ][ j ] = num[ i - 1 ][ j ] + 1 ; 
            } 
            else 
            {
                if ( num[ i ][ j - 1 ] ) 
                {
                    num[ i ][ j ] = num[ i ][ j - 1 ] + 1 ; 
                }
                else num[ i ][ j ] = 1 ; 
            }
            // cout << i << ' ' << j << ' ' << num[ i ][ j ] << '\n' ; 
            pos[ num[ i ][ j ] ][ ++ nump[ num[ i ][ j ] ] ] = { i , j } ; 
        }
    }
    // for ( int i = 1 ; i <= n ; ++ i ) 
    // {
    //     for ( int j = 1 ; j <= m ; ++ j )
    //     {
    //         cout << setw( 5 ) << num[ i ][ j ] << ' ' ; 
    //     }
    //     cout << '\n' ; 
    // }
    if ( a[ 1 ][ 1 ] != a[ n ][ m ] )
    {
        cout << 0 ; 
        return 0 ; 
    }
    int xi , yi , xj , yj ; 
    int len = n - 1 + m , mid = ( n + m ) >> 1 , lenk = n + m ; 
    for ( int i = mid ; i < lenk ; ++ i )
    {
        if ( i == mid && ( n - 1 + m ) % 2 == 1 ) 
        {
            for ( int j = 1 ; j <= nump[ i ] ; ++ j )
            {
                dp[ pos[ i ][ j ].x ][ pos[ i ][ j ].y ][ pos[ i ][ j ].x ] = 1 ; 
            }
            continue ; 
        }
        for ( int j = 1 ; j <= nump[ i ] ; ++ j )
        {
            xi = pos[ i ][ j ].x , yi = pos[ i ][ j ].y ; 
            for ( int k = 1 ; k <= nump[ lenk - i ] ; ++ k )
            {
                xj = pos[ lenk - i ][ k ].x , yj = pos[ lenk - i ][ k ].y ; 
                if ( a[ xi ][ yi ] == a[ xj ][ yj ] && xi >= xj && yi >= yj && xi > 0 && xj > 0 && yi > 0 && yj > 0 ) 
                {
                    pd( xj , yj , xi , yi , lenk ) ; 
                }
            }
        }
    } 
    cout << dp[ n ][ m ][ 1 ] << '\n' ; 
}

结尾撒花 \(\color{pink}✿✿ヽ(°▽°)ノ✿\)

posted @ 2024-03-08 15:26  HANGRY_Sol&Cekas  阅读(12)  评论(0编辑  收藏  举报