题目链接

比较容易想到用f[i][j]表示走了i步后到达j点的方案数,但是题目要求不能走上一条走过的边

如果这样表示是不好转移的

可以考虑边,f[i][j]表示走了i步后到达第j条边的方案数,那么有 f[i][j] = ∑f[i-1][k] (边k能直接到达边j)

只要不走反向边,就保证了不会走上一条边了

步数很大,而这个方程显然是可以通过矩阵快速幂加速转移的

求初始边矩阵的t-1次方幂t',然后用系数矩阵(与src相连的边)乘以t',即为走了t条边后的方案数

(这个系数矩阵是为了只保留矩阵中起点是src的路径)

最终答案为所有与des相连的边的dp值

一条边肯定要拆成两条有向边

注意异或运算级比!=还低。。

O((2m)^3logt)=5e7 得卡卡常

为什么自带大常数= =有人帮忙看下吗。。

//1368kb	2900ms
#include <cstdio>
#include <cctype>
#define gc() getchar()
#define mod 45989//真的略快
const int N=150;//,mod=45989; int n,m,K,src,des,Enum,H[70],nxt[N],to[N];
struct Matrix
{
int A[N][N];
// void Clear() {memset(A,0,sizeof A);}
Matrix operator *(const Matrix &a)const
{
Matrix res;
for(int i=1; i<=m; ++i)
for(int j=1; j<=m; ++j)
{
res.A[i][j]=0;
for(int k=1; k<=m; ++k)
(res.A[i][j]+=A[i][k]*a.A[k][j])%=mod;
}
return res;
// for(int i=1; i<=m; ++i)
// for(int k=1; k<=m; ++k)
// if(A[i][k])//优化技巧 先枚举k 于是可以判是否为0 -> 于是更慢了-- 应该是洛谷评测的问题吧。。
// for(int j=1; j<=m; ++j)
// res.A[i][j]+=A[i][k]*a.A[k][j]%mod,
// res.A[i][j]>=mod ? res.A[i][j]-=mod : 0;
}
}S,tmp; inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
inline void AddEdge(int u,int v)
{
to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum;
to[++Enum]=u, nxt[Enum]=H[v], H[v]=Enum;
}
Matrix FP(Matrix x,int k)
{
Matrix t=x; --k;
for(; k; k>>=1,x=x*x)
if(k&1) t=t*x;
return t;
} int main()
{
Enum=1;
n=read(),m=read(),K=read(),src=read(),des=read();
for(int u,v,i=1; i<=m; ++i) u=read(),v=read(),AddEdge(u,v);
m=Enum;
for(int i=H[src]; i; i=nxt[i]) S.A[1][i]=1;//拿1做起点 感觉好玄学啊。。
for(int i=2; i<=m; ++i)
for(int j=H[to[i]]; j; j=nxt[j])//与边i直接相邻的边即边的端点所连的边
if(i!=(j^1)) tmp.A[i][j]=1;//++tmp.A[i][j];//这个是不需要+的,因为已经把每条边都拆了
// if(i^j^1) tmp.A[i][j]=1;
tmp=FP(tmp,K-1);
S=S*tmp;
int res=0;
for(int i=H[des]; i; i=nxt[i]) res+=S.A[1][i^1];//起点到 能到终点的边
printf("%d",res%mod); return 0;
}

另外如果没有不走前一条边的限制是不是可以倍增Floyd

考试的时候强行看漏句子 然后15min写完以为A了==

#include <cstdio>
#include <cctype>
#include <cstring>
#define gc() getchar()
const int N=30,mod=45989; int n,m,K,src,des,f[N][N],tmp[N][N],ans[N][N]; inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
void Mult(int a[N][N],int b[N][N])
{
memset(tmp,0,sizeof tmp);
for(int k=0; k<n; ++k)
for(int i=0; i<n; ++i)
for(int j=0; j<n; ++j)
tmp[i][j]+= a[i][k]*b[k][j]%mod,
tmp[i][j]>=mod ? tmp[i][j]-=mod : 0;
}
//void Print(int a[N][N])
//{
// puts("Debug");
// for(int i=0; i<n; ++i,putchar('\n'))
// for(int j=0; j<n; ++j) printf("%d ",a[i][j]);
//} int main()
{
n=read(),m=read(),K=read()-1,src=read(),des=read();
for(int u,v,i=1; i<=m; ++i)
u=read(),v=read(),++f[u][v],++f[v][u];
for(int i=0; i<n; ++i)
for(int j=0; j<n; ++j) ans[i][j]=(f[i][j]%=mod);
while(K)
{
if(K&1) Mult(ans,f), memcpy(ans,tmp,sizeof tmp);
K>>=1, Mult(f,f), memcpy(f,tmp,sizeof tmp);
// printf("now K:%d\n",K);
}
printf("%d",ans[src][des]); return 0;
}

BZOJ.1875.[SDOI2009]HH去散步(DP 矩阵乘法)的更多相关文章

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

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

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

    首先,题意就把我们引向了矩阵乘法,注意边长m<=60,那么就按边建图,变成一个120个点的图,然后乱搞就行了。 PS:WA了N久改了3次终于A了QAQ CODE: #include<cst ...

  3. BZOJ 1875 [SDOI2009]HH去散步 ——动态规划 矩阵乘法

    发现t非常大,所以大概就是快速幂一类的问题了, 然后根据k^3logn算了算,发现k大约是边数的时候复杂度比较合适. 发现比较麻烦的就是前驱的记录,所以直接把边看做点,不能走反向边,但是可以走重边,然 ...

  4. 1875. [SDOI2009]HH去散步【矩阵乘法】

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

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

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

  6. bzoj 1875: [SDOI2009]HH去散步 -- 矩阵乘法

    1875: [SDOI2009]HH去散步 Time Limit: 20 Sec  Memory Limit: 64 MB Description HH有个一成不变的习惯,喜欢饭后百步走.所谓百步走, ...

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

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

  8. bzoj 1875 [SDOI2009]HH去散步(矩乘)

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

  9. [SDOI2009]HH去散步 「矩阵乘法计数」

    计数问题也许可以转化为矩阵乘法形式 比如若该题没有不能在一条边上重复走的条件限制,那么直接将邻接矩阵转化为矩阵乘法即可 故 矩阵乘法计数 对于计数问题,若可以将 \(n\) 个点表示成 \(n \ti ...

随机推荐

  1. Potential Pythonic Pitfalls

    Potential Pythonic Pitfalls Monday, 11 May 2015 Table of Contents Not Knowing the Python Version Obs ...

  2. py-faster-rcnn + opencv3.0.0 + ubuntu16.04配置(CPU模式)

    最近开始做行人检测,因此开始接触faster-rcnn,这里贴上配置教程(亲测可行),不过是基于cpu的,蓝瘦... 参考博客:http://www.tuicool.com/articles/nYJr ...

  3. k64 datasheet学习笔记3---Chip Configuration之System modules

    1.前言 本文主要介绍芯片配置的系统模块的内容 2.SIM配置 TODO 3.SMC配置 TODO 4.PMC配置 TODO 5.LOW-LEAKAGE WAKEUP单元配置 TODO 6.MCM配置 ...

  4. hping网络安全工具的安装及使用

    hping是用于生成和解析TCPIP协议数据包的开源工具.创作者是Salvatore Sanfilippo.目前最新版是hping3,支持使用tcl脚本自动化地调用其API.hping是安全审计.防火 ...

  5. 调试Windows Service

    调试Windows Service 使用一般的调试方法调试不了Windows Servers,所以参考了一些调试方法 我服务源码中使用了Timer,注意不能使用工具箱内的Timer,用System.T ...

  6. Linux 快速删除已输入的命令

    从输入模式到命令模式: 按”:“到最后一行,再按ctrl+z 就好了 history 显示命令历史列表 ↑(Ctrl+p) 显示上一条命令 ↓(Ctrl+n) 显示下一条命令 !num 执行命令历史列 ...

  7. Fiddler抓包8-打断点(bpu)

    前言 先给大家讲一则小故事,在我们很小的时候是没有手机的,那时候跟女神聊天都靠小纸条.某屌丝A男对隔壁小王的隔壁女神C倾慕已久,于是天天小纸条骚扰,无奈中间隔着一个小王,这样小王就负责传小纸条了.有一 ...

  8. python 全栈开发,Day53(jQuery的介绍,jQuery的选择器,jQuery动画效果)

    js总结 js: 1.ECMAScript5 ES5语法 2.DOM CRUD 获取 3种方式 id tag className //面向对象 对象 : 属性和方法 某个对象中 function $( ...

  9. 遍历集合的Iterator删除其中的元素

    package list; import java.util.LinkedList; /* * 遍历集合的时候删除其中的元素 从后往前删,每次都删除的是最后一个元素,不涉及移位 */public cl ...

  10. oracle表分区的,分区操作,分区查询,子分区查询

    一.摘要 有关表分区的一些维护性操作: 注:分区根据具体情况选择. 表分区有以下优点: 1.数据查询:数据被存储到多个文件上,减少了I/O负载,查询速度提高. 2.数据修剪:保存历史数据非常的理想. ...