题面

传送门

正文

其实就是让你求有多少条长度为t的路径,但是有一个特殊条件:不能走过一条边以后又立刻反着走一次(如果两次经过同意条边中间隔了别的边是可以的)

如果没有这个特殊条件,我们很容易想到dp做法:设$dp\left[i\right]\left[j\right]$表示第i个时刻(初始算0),走到第j个点的答案总数

但是这里要限制不能反复走,那么直接设点会导致信息丢失

那我们怎么样才能让保存当前所在点的情况下,不丢失最后一条边的信息呢?

答案非常显然,我们只要设$dp\left[i\right]\left[j\right]$表示第i个时刻(初始算0),走到第j条边的终点(也就是刚刚经过了第j条边到达这里)的答案总数,就可以了

此时我们因为知道第j条边的所有信息,而第j条边的信息中又包括了当前所在节点,所以我们继续转移需要的信息都收集全了

转移就是从当前点$u$开始,枚举从$u$出发的边$k$,向$dp\left[i+1\right]\left[to\left(k\right)\right]$转移即可

然而这里有个问题:T太大了,直接转移肯定爆炸,那怎么办呢?

我们观察可得,对于每个$dp\left[i\right]\left[j\right]$,只要$j$确定了,那么他应该往哪些状态转移也就确定了,同时这个转移一定是线性的(也就是$dp$这一项一定是一次的)

那我们还等什么呢?矩阵快速幂上啊!

我们构造转移矩阵B和初始状态矩阵A,但是这里又有一个问题:初始只有一个出发节点,并没有不能走哪条边的限制,但是转移矩阵B又依赖于这个限制,怎么办呢?

这好说,我们只要把A矩阵从所有$dp\left[0\right]\left[j\right]$变成所有$dp\left[1\right]\left[j\right]$就好了

这时答案矩阵$C=A\ast B^{t-1}$

只要取出答案矩阵中所有终点是给定终点的边的答案之和,输出即可

Code

写了结构体重载运算符......慢死

还好加了读入优化苟过去了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
inline ll read(){
ll re=0,flag=1;char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-') flag=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
return re*flag;
}
ll MOD=45989;
ll n,m,op,ed,tt,cnt=0,first[110];
struct edge{//邻接表存边
ll next,to;
}a[150];
inline void add(ll u,ll v){//矩阵结构体
a[++cnt]=(edge){first[u],v};first[u]=cnt;
a[++cnt]=(edge){first[v],u};first[v]=cnt;
}
struct ma{
ll a[150][150],n,m;
ma(){memset(a,0,sizeof(a));n=m=0;}
void clear(){memset(a,0,sizeof(a));n=m=0;}
const ma operator *(const ma &b){
ma re;re.n=n;re.m=b.m;ll i,j,k;
for(i=1;i<=n;i++){
for(k=1;k<=m;k++){
if(!a[i][k]) continue;
for(j=1;j<=b.m;j++){
re.a[i][j]+=(a[i][k]*b.a[k][j]);
re.a[i][j]%=MOD;
}
}
}
return re;
}
const void operator =(const ma &b){
n=b.n;m=b.m;ll i,j;
for(i=1;i<=n;i++) for(j=1;j<=m;j++) a[i][j]=b.a[i][j];
}
}A,B;
void qpow(ma &x,ma y,ll T){
while(T){
if(T&1) x=x*y;
y=y*y;T>>=1;
}
}
ll o(ll x){return ((x%2)?(x+1):(x-1));}//求一条边的反向边(因为我是一开始编号的,所以不方便直接异或)
int main(){
memset(first,-1,sizeof(first));ll i,t1,t2,j,u;
n=read();m=read();tt=read();op=read();ed=read();op++;ed++;
for(i=1;i<=m;i++){
t1=read();t2=read();t1++;t2++;
add(t1,t2);
}
A.n=1;A.m=B.m=B.n=cnt;
for(j=1;j<=cnt;j++){//构造转移矩阵
u=a[j].to;
for(i=first[u];~i;i=a[i].next){
if(i==o(j)) continue;
B.a[j][i]+=1;
}
}
for(i=first[op];~i;i=a[i].next){//构造初始矩阵
A.a[1][i]+=1;
}
qpow(A,B,tt-1);ll ans=0;
for(i=first[ed];~i;i=a[i].next){//统计答案
ans=(ans+A.a[1][o(i)])%MOD;
}
printf("%lld",ans);
}

[bzoj1875][SDOI2009] HH去散步 [dp+矩阵快速幂]的更多相关文章

  1. BZOJ 1875: [SDOI2009]HH去散步( dp + 矩阵快速幂 )

    把双向边拆成2条单向边, 用边来转移...然后矩阵乘法+快速幂优化 ------------------------------------------------------------------ ...

  2. 【SDOI2009】HH去散步(矩阵快速幂)

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

  3. BZOJ.1875.[SDOI2009]HH去散步(DP 矩阵乘法)

    题目链接 比较容易想到用f[i][j]表示走了i步后到达j点的方案数,但是题目要求不能走上一条走过的边 如果这样表示是不好转移的 可以考虑边,f[i][j]表示走了i步后到达第j条边的方案数,那么有 ...

  4. BZOJ_1875_[SDOI2009]HH去散步_矩阵乘法

    BZOJ_1875_[SDOI2009]HH去散步_矩阵乘法 Description HH有个一成不变的习惯,喜欢饭后百步走.所谓百步走,就是散步,就是在一定的时间 内,走过一定的距离. 但 是同时H ...

  5. BZOJ-1875 HH去散步 DP+矩阵乘法快速幂

    1875: [SDOI2009]HH去散步 Time Limit: 20 Sec Memory Limit: 64 MB Submit: 1196 Solved: 553 [Submit][Statu ...

  6. bzoj1875: [SDOI2009]HH去散步

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

  7. bzoj1875 [SDOI2009]HH去散步 矩阵快速幂

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=1875 题解 如果没有这个"不能立刻沿着刚刚走来的路走回",那么这个题就是一 ...

  8. 【题解】 bzoj1875: [SDOI2009]HH去散步 (动态规划+矩阵乘法)

    bzoj1875,懒得复制,戳我戳我 Solution: 看到这道题,看的出是个dp,每个点\(t\)时刻到达的方案数等于\(t-1\)到连过来的点方案数之和 但又因为题目有要求不能走一样的边回去不是 ...

  9. [难题题解] [BZOJ1875] [SDOI2009] HH去散步

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

随机推荐

  1. c语言数字图像处理(四):灰度变换

    灰度变换 灰度变换函数 s = T(r)   其中r为输入图像在(x, y)点处的灰度值,s为输出图像在(x, y)点处的灰度值 灰度变换的作用 上图所示的两幅T(s)函数的图像曲线,第一幅图可以增强 ...

  2. WinDbg使用学习

    拿到软件崩溃之后产生的crash文件,后缀名为dump 使用winDbg的File-----> Open Crash Dump 打开Crash文件 File---------> Symbo ...

  3. sqli-labs学习笔记 DAY6

    DAY 6 sqli-labs lesson 30 与上一题一样,需要用到HPP 查看源代码,参数两边加上了双引号,直接使用lesson 26a与lesson 27a的脚本即可 sqli-labs l ...

  4. tree命令详解

    基础命令学习目录首页 原文链接:http://man.linuxde.net/tree -a:显示所有文件和目录:-A:使用ASNI绘图字符显示树状图而非以ASCII字符组合:-C:在文件和目录清单加 ...

  5. Mongodb For Mac OSX && 登录验证

    题外话:尽管有不少人贴出了 <我不用mongodb的十大理由> 等系列文章,但是 NoSQL 的发展不会因此而止步, mongodb 是 NoSQL 的典型代表,楼主还是抱乐观态度的,有人 ...

  6. LIFI热火下的VLC基本链路、标准及发展问题

    和白炽及荧光灯相比,白光发光二极管(LED)具有寿命长.光效高.功耗低.无辐射.安全性好.可靠性高等特点,被称为"绿色照明"并得到迅猛发展.白光LED在未来市场极具竞争力.世界范围 ...

  7. 读书笔记之java编程思想2

    今天将第一章余下的部分读完了,余下部分讲解了java单继承的特点,单继承保证了所有的子类都有一个基类,这使得java所实现的垃圾回收器的实现变得简单了很多,单继承保证了所有的对象都具有一些功能,使得参 ...

  8. 标头 header()函数的用法

    头 (header) 是服务器以 HTTP 协议传 HTML 资料到浏览器前所送出的字串,在标头与 HTML 文件之间尚需空一行分隔. 范例一: 本例使浏览器重定向到 PHP 的官方网站. <? ...

  9. MongoDB安装笔记

    2017年11月17日,在Windows Service 2008R2上成功安装MongoDB. 版本:mongodb-win32-x86_64-2008plus-ssl-3.4.6-signed.m ...

  10. Beta阶段DAY5

    一.提供当天站立式会议照片一张 二.每个人的工作 1.讨论项目每个成员的昨天进展 刘阳航:改进UI,美化界面. 林庭亦:优化代码结构 郑子熙:改进UI,美化界面. 陈文俊:优化代码结构 2.讨论项目每 ...