TC13986 SubRectangles加强版

news/2026/1/20 19:49:38/文章来源:https://www.cnblogs.com/cdx1221/p/19508615

\(A\) 的范围由 \(4\) 加强到了 \(24\)

Problem

给定 \(H\)\(W\) 列的矩阵 \(a\),每个位置可以填 \(0\)\(1\),一个矩阵合法当且仅当其任意一个 \(A\times B\) 的子矩阵的和相同,求合法矩阵数。

\(H,W\le 10^9,A\le 24,B\le 4\)

Solution

对于一个点 \((i,j)\),如果 \((i-A,j),(i,j-B),(i-A,j-B)\) 已经确定,则这个格子唯一确定。证明:

上图为 \(4\)\(A\times B\) 的矩形,于是有 \(A+E+H=E+B+F=H+C+G=F+G+D\),从而有 \(A+E=C+G\)\(D+G=B+E\),化简后有 \(D=B+C-A\)

那么只需要填完前 \(A\) 行和前 \(B\) 列就可以唯一确定整个矩形。

但是会有不合法的情况,也就是 \(a_{i-A,j}=a_{i,j-B}=1-a_{i-A,j-B}\) 时, \(a_{i,j}\)\(-1\)\(2\)

为了进一步分析性质,将 \((i,j)\)\(i\bmod A\)\(j\bmod B\) 分组后拆成 \(A\times B\) 个矩阵,每个重标号为矩阵 \(b\)。那么上述限制变为 \(b_{i,j}=b_{i-1,j}+b_{i,j-1}-b_{i-1,j-1}\)\(b\) 矩阵合法的条件是 \(b_{i-1,j}= b_{i-1,j-1}\)\(b_{i,j-1}=b_{i-1,j-1}\)

引理:若 \(i>0,j>0\),则 \(b_{i,j}=b_{i,0}+b_{0,j}-b_{0,0}\)

证明:按 \(i,j\) 从小到大归纳,对于 \((i',j')\ne (i,j)\),若 \(i'\le i\)\(j'\le j\) 则结论成立,要证 \((i,j)\) 成立。

  1. \(i>1,j>1\),则 \(b_{i,j}=b_{i-1,j}+b_{i,j-1}-b_{i-1,j-1}=b_{i,0}+b_{0,j}-b_{0,0}\)
  2. \(i=1,j=1\),显然成立。
  3. \(i=1\),则 \(b_{i,j}=b_{0,j}+b_{i,j-1}-b_{0,j-1}=b_{i,0}+b_{0,j}-b_{0,0}\)
  4. \(j=1\),与 \(i=1\) 同理。

于是矩阵合法转化为任意 \(i,j>0\),有 \(b_{i,0}= b_{0,0}\)\(b_{0,j}=b_{0,0}\),从而推出要不然第 \(0\) 行全等于 \(b_{0,0}\),要不然第 \(0\) 列全等于 \(b_{0,0}\)

回到原问题,考虑前 \(A\times B\) 个格子,每个格子有三种选择,分别是:行相同,列相同,都相同,记作 \(1,2,3\)

考虑如果确定了每个格子的选择,如何计算方案数。

因为有 \(3\) 类格子,所以需要容斥,容斥系数为 \((-1)^{x}\),其中 \(x\)\(3\) 类格子的个数。

现在的限制是,第 \(i\) 行前 \(B\) 个的和要与第 \(i+A\) 行前 \(B\) 个的和相同,列也有同样的限制。

因为 \(3\) 类格子不影响限制,所以方案数先乘 \(2^x\),然后就可以不管 \(3\) 类格子。

考虑行列相互独立,拆开来算,以行的限制计算为例:

记与第 \(i\)\(\bmod A\) 相同的行有 \(w\) 个,这个可以 \(O(1)\) 算。记第 \(i\) 行有 \(j\)\(1\) 类格子,\(2\) 类格子和 \(3\) 类格子由于所有行在这列一样,所以不用管。

枚举 \(j\)\(1\) 类格子有 \(k\) 个选 \(1\),则每行独立且都要选 \(k\) 个,方案数 \(\dbinom{j}{k}^{w}\),所以总贡献为 \(\sum\limits_{k=0}^{j}\dbinom{j}{k}^{w}\)

每个 \(\bmod A\) 不同的行之间独立,所以贡献乘起来就行。

对于列的计算是几乎一致的,于是我们有 \(O(3^{AB}Poly)\) 的做法。

下面这份代码有很多东西没预处理,所以无法通过 \(A,B\le 4\),但这不重要。

#include<bits/stdc++.h>
using namespace std;
#define int long long
int H,W,A,B,ans,a[30][5],C[50][50];
const int mod=998244353;
int q_pow(int x,int y){if(!y) return 1;int z=q_pow(x,y>>1);if(y&1) return z*z%mod*x%mod;else return z*z%mod;
}
void solve(){int cnt=0,sum=1;for(int i=1;i<=A;i++){for(int j=1;j<=B;j++){if(a[i][j]==3){cnt++;sum=sum*2%mod;}}}for(int i=1;i<=A;i++){int x=0,w=(H-i)/A+1,y=0;for(int j=1;j<=B;j++) if(a[i][j]==1) x++;for(int j=0;j<=x;j++){y=(y+q_pow(C[x][j],w))%mod;}sum=sum*y%mod;}for(int i=1;i<=B;i++){int x=0,w=(W-i)/B+1,y=0;for(int j=1;j<=A;j++) if(a[j][i]==2) x++;for(int j=0;j<=x;j++){y=(y+q_pow(C[x][j],w))%mod;}sum=sum*y%mod;}ans=(ans+sum*(cnt&1?mod-1:1))%mod;
}
void dfs(int x,int y){if(x>A){solve();return;}if(y>B){dfs(x+1,1);return;}a[x][y]=1;dfs(x,y+1);a[x][y]=2;dfs(x,y+1);a[x][y]=3;dfs(x,y+1); 
}
signed main(){for(int i=0;i<=30;i++){C[i][0]=1;for(int j=1;j<=i;j++) C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;}cin>>H>>W>>A>>B;if(A>H || B>W){cout<<q_pow(2,H*W);return 0;}dfs(1,1);cout<<ans;return 0;
}

考虑如何优化,这一步比较自然,观察上面的贡献计算,可以发现我们只关心每行有几个 \(1\) 类格子,每列有几个 \(2\) 类格子,以及每个 \(3\) 类格子带来 \(-2\) 的贡献。

因为 \(B\) 很小,考虑从上往下 dp,记 \(f_{i,S}\) 表示当前在第 \(i\) 行,每列 \(2\) 类格子数量的状态为 \(S\) 的方案数。

枚举下一行哪些列选 \(2\) 类格子,下一行选了几个 \(1\) 类格子后即可转移,由于转移种类很少,预处理后容易做到 \(O((A+1)^{B}A2^B)\) 的复杂度。

这东西也容易用轮廓线 dp 做到 \(O((A+1)^{B}AB^2)\) 的复杂度,只需要在状态中多记一个这一行选了几个 \(1\) 类格子即可。

下面是 \(O((A+1)^{B}A2^B)\) 的代码。

#include<bits/stdc++.h>
using namespace std;
#define int long long
int H,W,A,B,ans,C[50][50],val[50][50],val2[50][50],f[30][400010];
const int mod=998244353;
int q_pow(int x,int y){if(!y) return 1;int z=q_pow(x,y>>1);if(y&1) return z*z%mod*x%mod;else return z*z%mod;
}
signed main(){for(int i=0;i<=30;i++){C[i][0]=1;for(int j=1;j<=i;j++) C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;}cin>>H>>W>>A>>B;if(A>H || B>W){cout<<q_pow(2,H*W);return 0;}int V=25*25*25*25;f[1][0]=1;for(int i=1;i<=A;i++){for(int j=0;j<=B;j++){int w=(H-i)/A+1;for(int x=0;x<=j;x++){int y=0;for(int k=0;k<=x;k++) y=(y+q_pow(C[x][k],w))%mod;y=y*q_pow(mod-2,j-x)%mod*C[j][x]%mod;val[i][j]=(val[i][j]+y)%mod;}}}for(int i=1;i<=B;i++){int w=(W-i)/B+1;for(int x=0;x<=A;x++) for(int j=0;j<=x;j++) val2[i][x]=(val2[i][x]+q_pow(C[x][j],w))%mod;}for(int i=1;i<=A;i++){for(int j=0;j<=V;j++){if(!f[i][j]) continue;for(int S=0;S<(1<<B);S++){int nj=j,cnt=B-__builtin_popcount(S);if(S&1) nj+=1;if(S&2) nj+=25;if(S&4) nj+=25*25;if(S&8) nj+=25*25*25;f[i+1][nj]=(f[i+1][nj]+f[i][j]*val[i][cnt])%mod;}}}for(int j=0;j<=V;j++){int k=j,sum=1;for(int i=1;i<=B;i++){sum=sum*val2[i][k%25]%mod;k/=25;}ans=(ans+f[A+1][j]*sum)%mod;}cout<<ans;return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1190558.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

高效数据架构:AI智能体帮数据架构师节省50%时间的秘诀

高效数据架构&#xff1a;AI智能体帮数据架构师节省50%时间的秘诀 引言&#xff1a;数据架构师的“时间困境” 凌晨1点&#xff0c;张磊盯着电脑屏幕上的第7版用户画像模型&#xff0c;揉了揉发涩的眼睛。作为某零售企业的数据架构师&#xff0c;他这周的工作像一团乱麻&#x…

关于严格维护2025博客之星年度评选活动公平性、打击刷票行为的公告

致所有参与2025博客之星活动的用户&#xff1a; 近期&#xff0c;我们荣幸地看到广大用户积极参与2025年度博客之星评选活动&#xff0c;我们的投票环节正在火热进行中&#xff0c;公平、公正、公开是CSDN一贯秉持并珍视的活动原则&#xff0c;是所有创作者心血与才华得以被平…

力扣14.最长公共前缀-纵向扫描法

&#x1f4cb; 题目描述编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀&#xff0c;返回空字符串 ""。示例 1&#xff1a;输入&#xff1a;strs ["flower","flow","flight"] 输出&#xff1a;"fl"示例…

用ppt绘制新的形状

通过PPT的组合和合并形状来绘制图片

新写的launch文件不能用tab补全

博客地址:https://www.cnblogs.com/zylyehuo/系统环境:ros1 noetc问题描述 launch文件不能用tab补全全部手敲是能运行的(执行完 source ./devel/setup.bash)解决方法Tab 补全失败的原因通常是 ROS 的包索引缓存(ros…

灵遁者诗歌:演员之镜 · 真实的演技

33. 【外卖员之镜 算法的脚注】他的运动轨迹&#xff0c;是城市血管里一颗被算法驱动的红细胞。准时率是他的血氧饱和度。在每一个红绿灯的间隙&#xff0c;他抬头望了一眼高楼里格子状的灯光。那其中一扇窗&#xff0c;是他今天送过的晚餐&#xff0c;也是他永远无法抵达的“…

20260120 - Linux驱动学习笔记:SPI子系统核心层到具体硬件驱动

详细追踪从spi.c中的函数接口 spi_write() 到 spi-imx.c 中具体硬件操作的完整调用链。 完整的函数调用链 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 第1步&#xff1a;应用层/设备驱动调用 ━━━━━━━…

从0到1成为大模型应用开发工程师:154万年薪岗位全解析

大模型应用开发工程师成为高薪职业&#xff08;154万年薪&#xff09;&#xff0c;因市场需求大而人才稀缺。这类工程师需掌握提示词工程、RAG、模型微调等技术&#xff0c;同时具备工程开发、AI理解和业务洞察的复合能力。文章提供分层学习路径和实战项目建议&#xff0c;帮助…

【物理应用】滑块-曲柄机构Matlab仿真

✅作者简介&#xff1a;热爱数据处理、建模、算法设计的Matlab仿真开发者。&#x1f34e;更多Matlab代码及仿真咨询内容点击 &#x1f517;&#xff1a;Matlab科研工作室&#x1f34a;个人信条&#xff1a;格物致知。&#x1f525; 内容介绍滑块 - 曲柄机构是机械传动领域最基础…

Serv-U+cpolar 让文件远程访问像连 Wi-Fi 一样简单

Serv-U 作为一款成熟的文件服务软件&#xff0c;核心功能围绕文件的共享与传输展开&#xff0c;支持 FTP/FTPS/SFTP 等多种协议&#xff0c;既能实现大文件断点续传&#xff0c;也能精细化分配用户权限&#xff0c;比如给普通员工只读权限、给管理人员修改权限&#xff0c;适配…

救命神器9个AI论文软件,自考学生轻松搞定毕业论文!

救命神器9个AI论文软件&#xff0c;自考学生轻松搞定毕业论文&#xff01; 自考论文写作的救星&#xff1a;AI工具如何帮你轻松应对 对于自考学生而言&#xff0c;撰写毕业论文是一项既复杂又耗时的任务。从选题、收集资料到撰写初稿、反复修改&#xff0c;每一步都可能让人感到…

【YOLO模型导出格式】大全

一行命令即可完成模型格式转换,了解每种格式的设计逻辑才能在实际部署中做出最佳选择。 YOLO模型在训练完成后,我们通常会将其从PyTorch格式导出为多种不同格式。这些格式不仅代表着不同的文件扩展名,更代表着为不同硬件平台和部署场景量身定做的优化策略。 从旨在最大化C…

【Science Advances】“安全可触”的低电压仿生人工肌肉,让机器人更柔、更轻、更安全

在机器人领域&#xff0c;刚性机器人虽然精度高&#xff0c;但在需要柔顺性、抗干扰性或高能效的复杂环境中往往力不从心。为此&#xff0c;科学家们致力于研发仿生机器人&#xff0c;尤其是模仿人体肌肉的“人工肌肉”。其中&#xff0c;电液致动器因具备与哺乳动物肌肉相媲美…

世界棋局:国家、巨头与文明的AI竞赛以及星链的最新发展

第三章&#xff1a;终极棋局&#xff1a;国家、巨头与文明的AI竞赛“当算力成为新军备&#xff0c;数据成为新疆域&#xff0c;星球级的智慧博弈已悄然布子。”在前两章&#xff0c;我们剖析了AI作为新物种的觉醒与其产业狩猎的逻辑。现在&#xff0c;让我们将视野拉升到星球尺…

【粉丝福利社】驾驭Gemini 3与Nano Banana:人人都是AI产品创客

你好&#xff0c;未来的创造者&#xff01; 2025 年&#xff0c;AI 编程已成爆发之势—— Cursor 年收入破 10 亿美元&#xff0c;斯坦福学生“不写一行代码”就能交作业…… 这背后&#xff0c;是一个明确的信号&#xff1a;编程的核心&#xff0c;正从“写代码”转向“定义需…

NLP技术视角下的论文优化:2026主流降重平台算法与效果深度横评 - 品牌观察员小捷

在AIGC检测算法全面升级的2026年,解决“哪个降重平台效果最好”的问题,已不再是简单的同义词替换(Synonym Replacement),而是涉及困惑度(Perplexity)对抗、语义重构(Semantic Refactoring)以及命名实体识别(…

如何下载Spring源码 - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

2. C语言核心语法 - 实践

2. C语言核心语法 - 实践2026-01-20 19:35 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; fo…

Linux驱动学习:验证MasterDriverDevice三方匹配成功

实验日志&#xff1a; [root100ask:/proc/device-tree]# find -name "oled" ./soc/aips-bus02000000/spba-bus02000000/ecspi02008000/oled [root100ask:/proc/device-tree]# cd /root/ [root100ask:~]# insmod oled_drv.ko [ 119.745706] 100ask_spi_oled_drv spi0…

华为笔记本安装Ubuntu系统,声卡没有声音的处理

从网站:https://github.com/Smoren/huawei-ubuntu-sound-fix/,下载安装包,并安装即可