小兔的话

欢迎大家在评论区留言哦~


HH去散步

题目限制

  • 内存限制:125.00MB
  • 时间限制:1.00s
  • 标准输入
  • 标准输出

题目知识点

  • 动态规划 \(dp\)
  • 矩阵
    • 矩阵乘法
    • 矩阵加速
    • 矩阵快速幂
  • 思维
    • 构造

题目来源

「 洛谷 」P2151 [SDOI2009]HH去散步


为了方便大家阅读通畅,题目可能略有改动,保证不会造成影响

题目

题目背景

HH 有个一成不变的习惯,喜欢在饭后散步,就是在一定的时间内,走一定的距离

同时, HH 是一个喜欢变化的人,她不会立刻沿着刚刚走过来的路走回去,她也希望每天走过的路径都不完全一样,她想知道每一天他究竟有多少种散步的方法

题目描述

现在 HH 送给你一张学校的地图,请你帮助她求出从地点 \(A\) 走到地点 \(B\) 一共有多少条长度为 \(T\) 的散步路径(答案对 \(45989\) 取模)

格式

输入格式

输入共 \(M + 1\) 行:

第 \(1\) 行:输入 \(5\) 个整数 \(N, \ M, \ T, \ A, \ B\);\(N\) 表示 学校里的路口的个数(编号为 \(0 \sim N - 1\)),\(M\) 表示 学校里的道路的条数,\(T\) 表示 HH 想要散步的距离,\(A\) 表示 散步的出发点, \(B\) 表示 散步的终点

接下来 \(M\) 行:每行 \(2\) 个用空格隔开的整数 \(u_i, \ v_i\);表示 长度为 \(1\) 的第 \(i\) 条路 连接 路口 \(u_i\)路口 \(v_i\)

输出格式

输出共一行:表示你所求出的答案(对 \(45989\) 取模)

样例

样例输入

4 5 3 0 0
0 1
0 2
0 3
2 1
3 2

样例输出

4

提示

数据范围

对于 \(30 \%\) 的数据:满足 \(N \leq 4, \ M \leq 10, \ T \leq 10\)

对于 \(100 \%\) 的数据:满足 \(N \leq 50, \ M \leq 60, \ T \leq 2 ^ {30}, \ u_i \neq v_i\)


思路

这道题如果没有 她不会立刻沿着刚刚走过来的路走回去 的限制,就可以根据点与点的关系先构造出一个 \(n * n\) 的矩阵 \(\mathrm{x}\)(\(\mathrm{x}[i][j]\) 表示从 \(i\) 走 \(1\) 步到 \(j\) 的方案数),累乘 \(T\) 次(就是走了 \(T\) 步),就用矩阵快速幂优化既可以通过了

现在就考虑加上这句话的限制后如何构造矩阵了


分析

考虑矩阵定义大致不变,即 \(\mathrm{x}[i][j]\) 表示从 \(i\) 走 \(1\) 步到 \(j\) 的方案数

由于有限制,就要记录刚刚走过来的路是哪一条

不妨把每条边对应的 \(u_i\) 和 \(v_i\) 拆成两个二元组 \(\mathrm{(node, id)}\),表示刚刚从第 \(\mathrm{id}\) 条路走到 \(\mathrm{node}\),也就是每条无向边 \((u_i \leftrightarrow, v_i)\) 分成两条有向边 \((u_i \to v_i)\) 和 \((v_i \to u_i)\),其中 \(\mathrm{node}\) 表示当前这条有向边的终点,\(\mathrm{id}\) 表示与之对应的无向边的编号

那么 \(\mathrm{x}[i][j] = 1\) 定义就是 第 \(i\) 个二元组 走 \(1\) 步到 第 \(j\) 个二元组 的方案数

其值只可能为 \(0\) 或 \(1\)(因为只走了 \(1\) 步),其中值为 \(1\) 的条件就是 \(\mathrm{id}_i \neq \mathrm{id}_j\) 且 \(\mathrm{node}_i\) 与 \(\mathrm{node}_j\) 有一条边

推出了矩阵,但是还有一个细节,就是第一步的方案数

起始点是没有上一条边的,所以需要预处理一下(这里相当于先走了一次)

预处理矩阵 \(\times\) 矩阵快速幂(\(T - 1\) 次,预处理走了一次)就可以得到最终的矩阵了

最后把 起始点(超级源点)终点(可能有多个,因为分了边) 的路径加起来取模就可以了


代码

#include <cstdio>
#include <cstring> int rint()
{
int x = 0, fx = 1; char c = getchar();
while (c < '0' || c > '9') { fx ^= ((c == '-') ? 1 : 0); c = getchar(); }
while ('0' <= c && c <= '9') { x = (x << 3) + (x << 1) + (c ^ 48); c = getchar(); }
if (!fx) return -x;
return x;
} const int MOD = 45989; const int MAX_N = 20;
const int MAX_M = 60; int N, M, T, A, B, node;
int e[MAX_M * 2 + 5][3]; struct Matrix
{
int mx[MAX_M * 2 + 5][MAX_M * 2 + 5]; Matrix () { memset(mx, 0, sizeof(mx)); } void init() { for (int i = 0; i <= node; i++) mx[i][i] = 1; } Matrix operator * (const Matrix &rhs) const
{
Matrix res;
for (int i = 0; i <= node; i++)
for (int j = 0; j <= node; j++)
for (int k = 0; k <= node; k++)
res.mx[i][j] = (res.mx[i][j] + mx[i][k] * rhs.mx[k][j]) % MOD;
return res;
}
} dp, quick; Matrix qpow(Matrix mx, int k)
{
Matrix res; res.init();
while (k > 0)
{
if (k & 1) res = res * mx;
mx = mx * mx; k >>= 1;
}
return res;
} int main()
{
N = rint(), M = rint(), T = rint();
A = rint() + 1, B = rint() + 1;
for (int i = 1; i <= M; i++)
{
e[i][0] = rint() + 1, e[i][1] = rint() + 1;
e[i + M][0] = e[i][1], e[i + M][1] = e[i][0];
if (e[i][0] == A) ++dp.mx[0][i];
if (e[i + M][0] == A) ++dp.mx[0][i + M];
}
node = M << 1;
for (int i = 1; i <= node; i++)
for (int j = 1; j <= node; j++)
if (i + M != j && i - M != j && e[i][1] == e[j][0]) ++quick.mx[i][j];
int ans = 0;
Matrix res = dp * qpow(quick, T - 1);
for (int i = 1; i <= node; i++)
if (e[i][1] == B) ans = (ans + res.mx[0][i]) % MOD;
printf("%d\n", ans);
return 0;
}

「 洛谷 」P2151 [SDOI2009]HH去散步的更多相关文章

  1. 洛谷P2151 [SDOI2009] HH去散步 [矩阵加速]

    题目传送门 HH去散步 题目描述 HH有个一成不变的习惯,喜欢饭后百步走.所谓百步走,就是散步,就是在一定的时间 内,走过一定的距离. 但是同时HH又是个喜欢变化的人,所以他不会立刻沿着刚刚走来的路走 ...

  2. [bzoj1875] [洛谷P2151] [SDOI2009] HH去散步

    Description HH有个一成不变的习惯,喜欢饭后百步走.所谓百步走,就是散步,就是在一定的时间 内,走过一定的距离. 但 是同时HH又是个喜欢变化的人,所以他不会立刻沿着刚刚走来的路走回. 又 ...

  3. 洛谷 P2151 [SDOI2009]HH去散步

    题目链接 思路 如果没有不能走上一条边的限制,很显然就是dp. 设f[i][j]表示到达i点走了j步的方案数,移到k点可以表示为f[k][j+1]+=f[i][j]. 如果有限制的话,可以考虑用边表示 ...

  4. P2151 [SDOI2009]HH去散步

    题目描述 HH有个一成不变的习惯,喜欢饭后百步走.所谓百步走,就是散步,就是在一定的时间 内,走过一定的距离. 但是同时HH又是个喜欢变化的人,所以他不会立刻沿着刚刚走来的路走回. 又因为HH是个喜欢 ...

  5. Luogu P2151 [SDOI2009]HH去散步 矩乘加速DP

    思路:矩乘优化DP 提交:3次(用了一个奇怪的东西导致常数过大) 题解: 如果可以走完正向边后又走反向边那就显然了,但是不能走,所以我们要将正反向边分别编号,区分正反向边. 所以这道题的矩阵是以边的编 ...

  6. AC日记——[SDOI2009]HH去散步 洛谷 P2151

    [SDOI2009]HH去散步 思路: 矩阵快速幂递推(类似弗洛伊德): 给大佬跪烂-- 代码: #include <bits/stdc++.h> using namespace std; ...

  7. 「 洛谷 」P2768 珍珠项链

    珍珠项链 题目限制 内存限制:125.00MB 时间限制:1.00s 标准输入输出 题目知识点 动态规划 \(dp\) 矩阵 矩阵乘法 矩阵加速 矩阵快速幂 题目来源 「 洛谷 」P2768 珍珠项链 ...

  8. 「 洛谷 」P4539 [SCOI2006]zh_tree

    小兔的话 推荐 小兔的CSDN [SCOI2006]zh_tree 题目限制 内存限制:250.00MB 时间限制:1.00s 标准输入输出 题目知识点 思维 动态规划 \(dp\) 区间\(dp\) ...

  9. bzoj1875: [SDOI2009]HH去散步

    终于A了...早上按自己以前的写法一直WA.下午换了一种写法就A了qwq #include<cstdio> #include<cstring> #include<iost ...

随机推荐

  1. Mycat Web监控工具

    简介 Mycat-web 是 Mycat 可视化运维的管理和监控平台,弥补了 Mycat 在监控上的空白.帮 Mycat 分担统计任务和配置管理任务.Mycat-web 引入了 ZooKeeper 作 ...

  2. CPF 入门教程 - 设计器和模板库的使用(五)

    CPF netcore跨平台UI框架 系列教程 CPF 入门教程(一) CPF 入门教程 - 数据绑定和命令绑定(二) CPF 入门教程 - 样式和动画(三) CPF 入门教程 - 绘图(四) CPF ...

  3. POJ1486模拟或者匈牙利变种

    题意:       有n个矩形,每个矩形上的某个位置上都有一个点,但是由于矩形是透明的,当一些矩形重叠在一起的时候就很可能分不清哪个点是那个矩形的,给你n个矩形的坐标,还有n个点的坐标,然后让你找出所 ...

  4. UVA11464偶数矩阵

    题意:       给你一个n*n的01矩阵,你的你的任务是吧尽量少的0变成1,使得每个元素的上下左右之和均为偶数(如果有的话),比如 0 0 0         0 1 0 1 0 0  ---&g ...

  5. HTTP自定义Header-(SOCKET-TCP)

      HTTP自定义Header-TCP 前几天弄一些东西,需要在发送http请求的时候自定义http头,找了几个库用着很不爽.有的把Cookie直接干掉了,还自己在头里加了版权,最后终于忍不了了.在网 ...

  6. php isset()与empty()的使用

    PHP isset函数作用 isset函数是检测变量是否设置. 格式:bool isset( mixed var [, mixed var [, ...]] ) 返回值: 若变量不存在则返回FALSE ...

  7. .NET并发编程-TPL Dataflow并行工作流

    本系列学习在.NET中的并发并行编程模式,实战技巧 本小节了解TPL Dataflow并行工作流,在工作中如何利用现成的类库处理数据.旨在通过TDF实现数据流的并行处理. TDF Block 数据流由 ...

  8. idea设置js为ES6

  9. 【微信小程序】--小程序中循环遍历(包括js中遍历和wxml中的遍历)

    文章为博主原创,纯属个人见解,如有错误欢迎指出. 如需转载,请注明出处. 在js中遍历 for (var index in res.data.infos) { res.data.infos[index ...

  10. Java反射机制以及动态代理

    Java反射机制以及动态代理 Java反射机制 含义与功能 Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类 ...