初三奥赛模拟测试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}✿✿ヽ(°▽°)ノ✿\)

初三奥赛模拟测试1--T1回文的更多相关文章

  1. 【佛山市选2013】JZOJ2020年8月7日提高组T1 回文子序列

    [佛山市选2013]JZOJ2020年8月7日提高组T1 回文子序列 题目 描述 回文序列是指左右对称的序列.例如1 2 3 2 1是回文序列,但是1 2 3 2 2就不是.我们会给定一个N×M的矩阵 ...

  2. 4.22 省选模拟赛 三元组 manacher 回文自动机

    容易发现可以枚举j 那么只需要计算出 l~j这段是回文串的l的和 以及j+1~r这段是回文串的r的和. 可以manacher 之后想要求出以j为右端点的回文串左端点的和 这个东西我们通过某个点为中心的 ...

  3. [CSP-S模拟测试]:ants(回滚莫队)

    题目描述 然而贪玩的$dirty$又开始了他的第三个游戏. $dirty$抓来了$n$只蚂蚁,并且赋予每只蚂蚁不同的编号,编号从$1$到$n$.最开始,它们按某个顺序排成一列.现在$dirty$想要进 ...

  4. 【20180807模拟测试】t1 function

    low逼的我也只能写这样的水题... 题面 对于一个整数,定义 f(x)为他的每个数位的阶乘的乘积.例如 f(135)=1! * 3! * 5! =720.给出一个数 a(可以包含前缀零),a 满足他 ...

  5. 「题解」NOIP模拟测试题解乱写II(36)

    毕竟考得太频繁了于是不可能每次考试都写题解.(我解释个什么劲啊又没有人看) 甚至有的题目都没有改掉.跑过来写题解一方面是总结,另一方面也是放松了. NOIP模拟测试36 T1字符 这题我完全懵逼了.就 ...

  6. [python]回答百度知道上的问题2000-2999之间的回文日

    因为百度知道的编辑器没有提供代码功能,将回复写入. 题目如下: 求2000到2999的所有回文日,例如20200202 用Python怎么做 回文年好求,回文日的话,年月日这咋存啊 思路一:遍历每一天 ...

  7. 10.1 csp-s模拟测试(b) X国的军队+排列组合+回文

    T1 X国的军队 贪心,按$b-a$的大小降序排序,然后就贪心吧 #include<iostream> #include<cstdio> #include<algorit ...

  8. [CSP-S模拟测试]:回文(hash+二维前缀和)

    题目描述 闲着无聊的$YGH$秒掉上面两道题之后,开始思考有趣的回文串问题了. 他面前就有一个漂浮着的字符串.显然$YGH$是会$manacher$的,于是他随手求出了这个字符串的回文子串个数.但是他 ...

  9. [CSP-S模拟测试]:回文串(hash+二分)

    题目描述 $ASDFZ$的机房中不仅有红太阳,还有蓝太阳和原谅色太阳.有一天,太阳们来到机房,发现桌上有不知道哪个蒟蒻放上的问题:令$F(A,B)$表示选择一个串$A$的非空前缀$S$和串$B$的非空 ...

  10. csp-s模拟测试10.1(b)X 国的军队,排列组合, 回文题解

    题面:https://www.cnblogs.com/Juve/articles/11615883.html X 国的军队: 好像有O(T*N)的直接贪心做法 其实多带一个log的二分也可以过 先对所 ...

随机推荐

  1. 嵌入式编程的 4 种模型:轮询、中断、DMA、通道

    轮询方式 对I/O设备的程序轮询的方式,是早期的计算机系统对I/O设备的一种管理方式.它定时对各种设备轮流询问一遍有无处理要求.轮流询问之后,有要求的,则加以处理.在处理I/O设备的要求之后,处理机返 ...

  2. 3款C#开源且实用的工具类库,工作效率提升利器!

    前言 在日常工作开发中工具类库是软件开发中不可或缺的一部分,它们通过提供代码重用.通用功能.隐藏复杂性.提高代码质量.扩展性等方面的优势,帮助开发者更高效.更稳定地构建软件应用程序.今天大姚给大家分享 ...

  3. SpringBoot实现单机锁和分布式锁

    1.使用Java的内置锁机制(单机锁) Java提供了synchronized关键字和java.util.concurrent.locks.Lock接口来实现锁. synchronized是Java语 ...

  4. 组件中 data 为什么是一个函数?

    如果两个实例引用同一个对象,当其中一个实例的属性发生改变时,另一个实例属性也随之改变,对象没有自己的作用域,只有当两个实例拥有自己的作用域时,才不会相互干扰. 这是因为JavaScript的特性所导致 ...

  5. Mac Docker设置国内镜像加速器

    安装docker 点我直达 设置国内加速镜像 { "experimental": false, "features": { "buildkit&quo ...

  6. CF717E

    这道题属于是那种看上去很有思路,然后无从下手,写了个dfs感觉实在是不行. 后面仔细看了一下,这个题是用的构造dfs,基本是树上dfs,时间复杂度是O(V+E) 新构造的一个参数作为根,整个dfs表示 ...

  7. 深入解析 Vue Router:构建单页面应用的利器

    Vue.js 是一个渐进式 JavaScript 框架,常用于构建用户界面.随着应用的复杂度增加,路由(Routing)变得越来越重要,这就是 Vue Router 的用武之地.Vue Router ...

  8. PowerBuilder现代编程方法X01:PowerPlume的X模式

    临渊羡鱼,不如退而结网. PB现代编程方法X01:PowerPlume的X模式 前言 PowerPlume是PowerBuilder深度创新的扩展开发框架(免费商用). 它不是一个大而全的类库(取决于 ...

  9. ModuleNotFoundError: No module named 'import_export'

    当你遇到 "ModuleNotFoundError: No module named 'import_export'" 错误时,这表示你的 Python 脚本或应用程序试图导入名为 ...

  10. [oeasy]python0069_帮助手册_pydoc_manual_document

    帮助手册 回忆上次内容   上次了解了注释 注释是为了让程序更可读 注释不会影响程序运行速度   注释分为两种 单行的 以#开头 不能是字符串当中的#   多行的 三个" 三个'     多 ...