初三奥赛模拟测试1--T1回文
初三奥赛模拟测试1--\(T1\)回文
题意
给定一个 \(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\) :
\]
对于这个题,我们还有另外的性质:
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回文的更多相关文章
- 【佛山市选2013】JZOJ2020年8月7日提高组T1 回文子序列
[佛山市选2013]JZOJ2020年8月7日提高组T1 回文子序列 题目 描述 回文序列是指左右对称的序列.例如1 2 3 2 1是回文序列,但是1 2 3 2 2就不是.我们会给定一个N×M的矩阵 ...
- 4.22 省选模拟赛 三元组 manacher 回文自动机
容易发现可以枚举j 那么只需要计算出 l~j这段是回文串的l的和 以及j+1~r这段是回文串的r的和. 可以manacher 之后想要求出以j为右端点的回文串左端点的和 这个东西我们通过某个点为中心的 ...
- [CSP-S模拟测试]:ants(回滚莫队)
题目描述 然而贪玩的$dirty$又开始了他的第三个游戏. $dirty$抓来了$n$只蚂蚁,并且赋予每只蚂蚁不同的编号,编号从$1$到$n$.最开始,它们按某个顺序排成一列.现在$dirty$想要进 ...
- 【20180807模拟测试】t1 function
low逼的我也只能写这样的水题... 题面 对于一个整数,定义 f(x)为他的每个数位的阶乘的乘积.例如 f(135)=1! * 3! * 5! =720.给出一个数 a(可以包含前缀零),a 满足他 ...
- 「题解」NOIP模拟测试题解乱写II(36)
毕竟考得太频繁了于是不可能每次考试都写题解.(我解释个什么劲啊又没有人看) 甚至有的题目都没有改掉.跑过来写题解一方面是总结,另一方面也是放松了. NOIP模拟测试36 T1字符 这题我完全懵逼了.就 ...
- [python]回答百度知道上的问题2000-2999之间的回文日
因为百度知道的编辑器没有提供代码功能,将回复写入. 题目如下: 求2000到2999的所有回文日,例如20200202 用Python怎么做 回文年好求,回文日的话,年月日这咋存啊 思路一:遍历每一天 ...
- 10.1 csp-s模拟测试(b) X国的军队+排列组合+回文
T1 X国的军队 贪心,按$b-a$的大小降序排序,然后就贪心吧 #include<iostream> #include<cstdio> #include<algorit ...
- [CSP-S模拟测试]:回文(hash+二维前缀和)
题目描述 闲着无聊的$YGH$秒掉上面两道题之后,开始思考有趣的回文串问题了. 他面前就有一个漂浮着的字符串.显然$YGH$是会$manacher$的,于是他随手求出了这个字符串的回文子串个数.但是他 ...
- [CSP-S模拟测试]:回文串(hash+二分)
题目描述 $ASDFZ$的机房中不仅有红太阳,还有蓝太阳和原谅色太阳.有一天,太阳们来到机房,发现桌上有不知道哪个蒟蒻放上的问题:令$F(A,B)$表示选择一个串$A$的非空前缀$S$和串$B$的非空 ...
- csp-s模拟测试10.1(b)X 国的军队,排列组合, 回文题解
题面:https://www.cnblogs.com/Juve/articles/11615883.html X 国的军队: 好像有O(T*N)的直接贪心做法 其实多带一个log的二分也可以过 先对所 ...
随机推荐
- QT学习:08 QString
--- title: framework-cpp-qt-08-QString EntryName: framework-cpp-qt-08-QString date: 2020-04-16 15:36 ...
- 七牛云 + PicGo
下载PicGo https://github.com/Molunerfinn/PicGo/releases/tag/v2.3.1 七牛云配置 1.AccessKey和SecretKey:可以在七牛云控 ...
- dig 命令详解及使用示例
一.背景知识 CNAME CNAME 是 Canonical Name 的缩写,它是 DNS(域名系统)记录的一种类型.CNAME 记录用于将一个域名映射(别名)到另一个域名.换句话说,当你访问一个设 ...
- spark共享变量---广播变量和累加变量
从三个方面来分析:1.什么时候使用,2.原理是什么3.性能上有什么优化 累加变量:--(自定义累加器很重要) 使用场景:累加器的一个常见用途是在调试时对作业执行过程中的事件进行计数,如:统计日志中空行 ...
- 对于三节点集群zookeeper配置步骤:
步骤一:干净的集群,全新的hdfs在第一台主机上配置配置文件core-site.xml:<configuration><property> <name>fs.def ...
- Mac Docker设置国内镜像加速器
安装docker 点我直达 设置国内加速镜像 { "experimental": false, "features": { "buildkit&quo ...
- 【进阶篇】一文搞清楚网页发起 HTTP 请求调用的完整过程
目录 前言 一.HTTP协议 1.1基本概念 1.2工作原理 二.请求过程 2.1域名解析 2.2TCP 连接 2.3发送 HTTP 请求 2.4服务器应答 2.5响应内容 2.6关闭连接 三.客户端 ...
- linux mysql 允许进行远程连接 比如 navicat
出于安全方面考虑默认只允许本机(localhost, 127.0.0.1)来连接访问.所以开启远程访问权限.登录mysqlmysql -uroot -pxxxxxx 1:GRANT ALL PRIVI ...
- WPF使用AppBar实现窗口停靠,适配缩放、全屏响应和多窗口并列(附封装好即开即用的附加属性)
在吕毅大佬的文章中已经详细介绍了什么是AppBar: WPF 使用 AppBar 将窗口停靠在桌面上,让其他程序不占用此窗口的空间(附我封装的附加属性) - walterlv 即让窗口固定在屏幕某一边 ...
- 【Vue】未读消息标记功能
页面展示的效果如图,需要定时更新未读消息 首先是后台的接口,查询未处理的消息数量 因为是七张消息表,数据我需要合在一起返回给前台: 这里使用UNION连接各个表 SELECT COUNT(*) AS ...