NC200324 魔改森林
题目
题目描述
曾经有一道叫做迷雾森林的题目,然而牛牛认为地图中的障碍太多,实在是太难了,所以删去了很多点,出了这道题。
牛牛给出了一个n行m列的网格图
初始牛牛处在最左下角的格点上(n+1,1),终点在右上角的格点(1,m+1)
现在它想知道,从起点走到终点,只能向上或向右走,一共有多少种走法呢?
需要注意的是,除了起点和终点外,其它的每个格点都有可能有障碍,无法通过。
请注意格子与格点的区别
输入描述
第一行三个整数n,m,k,表示格子的大小,以及有k个障碍
接下来k行(若k=0则无此行),每行一个格点坐标(x,y),表示每个障碍的位置
输出描述
仅一行,一个整数表示答案对998244353取模的值
示例1
输入
4 5 1
3 4
输出
66
说明
示例2
输入
12345 54321 2
123 321
456 654
输出
801071140
示例3
输入
114 514 3
19 19
8 10
65 45
输出
567102428
备注
题解
知识点:计数dp,容斥原理,DAG上dp。
按数据点分治,先将 \(x\) 变换为 \(n+1-x\) ,这样起点就是 \((1,1)\) ,终点就是 \((n+1,m+1)\) 。
当 \(n,m \leq 1000\) 时,就是朴素的路径计数dp,不多讲了。
当 \(n,m > 1000\) 时,注意到 \(k\) 很小,可以考虑容斥原理,求经过至少一个障碍物的路径总数,再用总路径数减去即可,复杂度是 \(O(k \cdot 2^k)\) 的。其中,从 \((x_1,y_1)\) 到 \((x_2,y_2)\) 的全部路径总数为 \(\dbinom{x_2 - x_1 + y_2 - y_1}{x_2 - x_1}\) 。
但我们发现,这里的容斥实际上大部分状态都是不合法的,因为要保证子集的障碍物满足二维偏序,才是一条合法的障碍物路径。然而,我们将障碍物满足的二维偏序图画出来,呈现的一定是个DAG,于是我们可以仿照之前的路径计数dp,再这个DAG上dp。
我们设 \(f_i\) 表示到第 \(i\) 个障碍物但不经过其他障碍物的路径总数。那么 \(f_i\) 等于到达它全部路径总数,减去能到达它的障碍物 \(j\) 的 \(f_j\) 即可。
为了保证在求 \(f_i\) 之前,所有能到达 \(i\) 的障碍物的答案都已经求完了,我们可以建一个DAG图进行拓扑序的dp,但实际上不需要这么做,我们可以仿照二维偏序(逆序对)的方法进行维护。
我们将障碍物按 \(x\) 坐标从小到大排序,这时候就维护了第一维的偏序。之后当我们枚举到 \(i\) ,我们只需要枚举 \(j\) 满足 \(j<i\) 的障碍物即可先保证了第一维的偏序,再检验第二维偏序即可。
最后,我们用总路径数减去所有障碍物的 \(f\) 即可。
时间复杂度 \(O(min\{nm,k^2\})\)
空间复杂度 \(O(nm+k)\)
代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int P = 998244353;
namespace Number_Theory {
const int N = 2e5 + 7;
int qpow(int a, ll k) {
int ans = 1;
while (k) {
if (k & 1) ans = 1LL * ans * a % P;
k >>= 1;
a = 1LL * a * a % P;
}
return ans;
}
int fact[N], invfact[N];
void init(int n) {
fact[0] = 1;
for (int i = 1;i <= n;i++) fact[i] = 1LL * i * fact[i - 1] % P;
invfact[n] = qpow(fact[n], P - 2);
for (int i = n;i >= 1;i--) invfact[i - 1] = 1LL * invfact[i] * i % P;
}
}
namespace CNM {
using namespace Number_Theory;
int C(int n, int m) {
if (n == m && m == -1) return 1; //* 隔板法特判
if (n < m || m < 0) return 0;
return 1LL * fact[n] * invfact[n - m] % P * invfact[m] % P;
}
}
/// 公式法求组合数,O(n),预处理阶乘及其逆元快速求出组合数
int calc(int x1, int y1, int x2, int y2) {
return CNM::C(x2 - x1 + y2 - y1, x2 - x1);
}
pair<int, int> obst[100007];
bool dt[1007][1007];
int f[1007][1007];
int ans[100007];
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n, m, k;
cin >> n >> m >> k;
for (int i = 1;i <= k;i++) {
int x, y;
cin >> x >> y;
obst[i] = { n + 1 - x + 1,y };
}
if (n <= 1000 && m <= 1000) {
for (int i = 1;i <= k;i++) {
auto [x, y] = obst[i];
dt[x][y] = 1;
}
f[0][1] = 1;
for (int i = 1;i <= n + 1;i++)
for (int j = 1;j <= m + 1;j++)
if (!dt[i][j]) f[i][j] = (f[i - 1][j] + f[i][j - 1]) % P;
cout << f[n + 1][m + 1] << '\n';
}
else {
Number_Theory::init(n + m + 2);
sort(obst + 1, obst + k + 1);
obst[++k] = { n + 1,m + 1 };
for (int i = 1;i <= k;i++) {
auto [x1, y1] = obst[i];
ans[i] = calc(1, 1, x1, y1);
for (int j = 1;j <= i - 1;j++) {
auto [x2, y2] = obst[j];
if (x2 > x1 || y2 > y1) continue;
(ans[i] -= 1LL * ans[j] * calc(x2, y2, x1, y1) % P - P) %= P;
}
}
cout << ans[k] << '\n';
}
return 0;
}
NC200324 魔改森林的更多相关文章
- 魔改——MDI多视图模板Tab/标签页 初始化/操作控件
==================================声明================================== 本文原创,转载在正文中显要的注明作者和出处,并保证文章的完 ...
- 魔改——MFC SDI程序 转换为 MDI程序
==================================声明================================== 本文原创,转载在正文中显要的注明作者和出处,并保证文章的完 ...
- 魔改——MFC MDI程序 定制 文档模板 运行时全部打开 禁用关闭按钮
==================================声明================================== 本文原创,转载在正文中显要的注明作者和出处,并保证文章的完 ...
- 【题解】BZOJ4241: 历史研究(魔改莫队)
[题解]BZOJ4241: 历史研究(魔改莫队) 真的是好题啊 题意 给你一个序列和很多组询问(可以离线),问你这个区间中\(\max\){元素出现个数\(\times\)元素权值} IOI国历史研究 ...
- Asp.Net Core Identity 骚断腿的究极魔改实体类
前言 默认的 Identity 实体类型在大多数时候已经基本够用,很多时候也只是稍微在 IdentityUser 类中增加一些自定义数据字段,比如头像.这次,我要向园友隆重介绍我魔改之后的 Ident ...
- 你没有见过的【高恪】船新版本(SX3000 NAT1 X86魔改)
最近魔改了高恪SX3000 X86,做了如下更改: 开启了SSH 集成了插件(酸酸乳.V2RXY.SMB等等) 开启了NAT1 DIY了主题 精简了官方内置的无用应用和模块 截图(建议右击图片,在新标 ...
- [7b2美化]柒比贰 魔改系列|7B2-分类封面添加波浪效果&每日诗词
本文转载自:钻芒博客 https://www.zmki.cn/5105.html 效果如图: 代码: 首先在style.css样式表里添加波浪样式 /*浪来了*/ .lang { overflow: ...
- 【题解】LOJ2462完美的集合(树DP 魔改Lucas)
[题解]LOJ2462完美的集合(树DP 魔改Lucas) 省选模拟考这个??????????????????? 题目大意: 有一棵树,每个点有两个属性,一个是重量\(w_i\)一个是价值\(v_i\ ...
- layui 魔改:富文本编辑器添加上传视频功能
甲方又整新需求了:富文本编辑器需要可以传视频. layui本身的富文本编辑器没有传视频的功能,所以,又到了咱们魔改的时候了. 友情提醒,富文本编辑器 layedit 只有layui的V1版有,V2版没 ...
- Hexo博客美化之蝴蝶(butterfly)主题魔改
Hexo是轻量级的极客博客,因为它简便,轻巧,扩展性强,搭建部署方便深受广大人们的喜爱.各种琳琅满路的Hexo主题也是被各种大佬开发出来,十分钦佩,向大佬仰望,大声称赞:流批!!! 我在翻看各种主 ...
随机推荐
- 每天学五分钟 Liunx 0001 | 存储篇:swap
swap swap ,内存交换空间,它是磁盘上的一块空间,主要作用是为了防止物理内存不足. CPU 从内存中读取数据.当内存的空间不足时, CPU 难以读取到数据,导致程序无法正常工作.所以诞生了 s ...
- jvisualm 结合 visualGC 进行jvm监控,并分析垃圾回收
本文为博主原创,未经允许不得转载 1.jvisualm 的使用 打开 jdk 安装目录bin目录下的 jvisualvm.exe 工具 2. visual GC插件的安装及监控分析 Visual GC ...
- vscode插件 - 浏览器中自动刷新 Live Server
- Vue2.x项目整合ExceptionLess监控
前言 一直以来我们都是用Sentry做项目监控,不过前段时间我们的Sentry坏掉了(我搞坏的) 但监控又是很有必要的,在sentry修好之前,我想先寻找一个临时的替代方案,同时发现网上关于Excep ...
- [转帖]MySQL如何在InnoDB中重建索引并更新统计数据?
https://geek-docs.com/mysql/mysql-ask-answer/356_mysql_how_can_i_rebuild_indexes_and_update_stats_in ...
- PG数据库存储验证
PG数据库存储验证 背景 最近学习了SQLServer数据库的varchar和nvarchar的存储 想到PG数据库其实没让选择字符集,也没有nvarchar 所以想学习一下nvarchar的使用情况 ...
- [转帖]docker exec 失败问题排查之旅
https://plpan.github.io/docker-exec-%E5%A4%B1%E8%B4%A5%E9%97%AE%E9%A2%98%E6%8E%92%E6%9F%A5%E4%B9%8B% ...
- [转帖]tidb-lightning 逻辑模式导入
https://docs.pingcap.com/zh/tidb/stable/tidb-lightning-configuration 本文档介绍如何编写逻辑导入模式的配置文件,如何进行性能调优等内 ...
- [转帖]python中input()、print()用法
https://www.cnblogs.com/lei3082195861/p/16967109.html 1.input()函数常涉及的强制类型转换 第一种是在键入时进行转换,例如:a = int( ...
- Linux 一行命令 仅显示某一个网卡的ip地址
最简答的方法 1. 先使用 ifconfig 查看网卡的设备名 2. 然后输入命令 ifconfig ens192 |grep 'inet ' |cut -d " " -f 10命 ...