BZOJ.1875.[SDOI2009]HH去散步(DP 矩阵乘法)
比较容易想到用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 矩阵乘法)的更多相关文章
- BZOJ 1875: [SDOI2009]HH去散步( dp + 矩阵快速幂 )
把双向边拆成2条单向边, 用边来转移...然后矩阵乘法+快速幂优化 ------------------------------------------------------------------ ...
- BZOJ 1875: [SDOI2009]HH去散步(矩阵乘法)
首先,题意就把我们引向了矩阵乘法,注意边长m<=60,那么就按边建图,变成一个120个点的图,然后乱搞就行了。 PS:WA了N久改了3次终于A了QAQ CODE: #include<cst ...
- BZOJ 1875 [SDOI2009]HH去散步 ——动态规划 矩阵乘法
发现t非常大,所以大概就是快速幂一类的问题了, 然后根据k^3logn算了算,发现k大约是边数的时候复杂度比较合适. 发现比较麻烦的就是前驱的记录,所以直接把边看做点,不能走反向边,但是可以走重边,然 ...
- 1875. [SDOI2009]HH去散步【矩阵乘法】
Description HH有个一成不变的习惯,喜欢饭后百步走.所谓百步走,就是散步,就是在一定的时间 内,走过一定的距离. 但 是同时HH又是个喜欢变化的人,所以他不会立刻沿着刚刚走来的路走回. 又 ...
- BZOJ_1875_[SDOI2009]HH去散步_矩阵乘法
BZOJ_1875_[SDOI2009]HH去散步_矩阵乘法 Description HH有个一成不变的习惯,喜欢饭后百步走.所谓百步走,就是散步,就是在一定的时间 内,走过一定的距离. 但 是同时H ...
- bzoj 1875: [SDOI2009]HH去散步 -- 矩阵乘法
1875: [SDOI2009]HH去散步 Time Limit: 20 Sec Memory Limit: 64 MB Description HH有个一成不变的习惯,喜欢饭后百步走.所谓百步走, ...
- BZOJ-1875 HH去散步 DP+矩阵乘法快速幂
1875: [SDOI2009]HH去散步 Time Limit: 20 Sec Memory Limit: 64 MB Submit: 1196 Solved: 553 [Submit][Statu ...
- bzoj 1875 [SDOI2009]HH去散步(矩乘)
Description HH有个一成不变的习惯,喜欢饭后百步走.所谓百步走,就是散步,就是在一定的时间 内,走过一定的距离. 但是同时HH又是个喜欢变化的人,所以他不会立刻沿着刚刚走来的路走回. 又因 ...
- [SDOI2009]HH去散步 「矩阵乘法计数」
计数问题也许可以转化为矩阵乘法形式 比如若该题没有不能在一条边上重复走的条件限制,那么直接将邻接矩阵转化为矩阵乘法即可 故 矩阵乘法计数 对于计数问题,若可以将 \(n\) 个点表示成 \(n \ti ...
随机推荐
- 【ARTS】01_03_左耳听风-20181126~1202
ARTS: Algrothm: leetcode算法题目 Review: 阅读并且点评一篇英文技术文章 Tip/Techni: 学习一个技术技巧 Share: 分享一篇有观点和思考的技术文章 Algo ...
- matplotlib 画图
matplotlib 画图 1. 画曲线图 Tompson = np.array([0, 0, 0, 0, 0.011, 0.051, 0.15, 0.251, 0.35, 0.44, 0 ...
- Linux下clock计时函数学习
平时在Linux和Winows下都有编码的时候,移植代码的时候免不了发现一些问题.1. 你到底准不准?关于clock()计时函数首先是一段简单的测试代码,功能为测试从文本文件读取数据并赋值给向量最后打 ...
- mysql系列三、mysql开启缓存、设置缓存大小、缓存过期机制
一.开启缓存 mysql 开启查询缓存可以有两种方法来开启一种是使用set命令来进行开启,另一种是直接修改my.ini文件来直接设置都是非常的简单的哦. 开启缓存,设置缓存大小,具体实施如下: 1.修 ...
- 【转】SourceInsight4破解笔记
时隔好多年,sourceinsight4以迅雷不及掩耳之势的来了.与3.5相比,sourceinsight4多了代码折叠以及文件标签功能,可谓是让sourceinsight迷兴奋了好几晚上.废话不多说 ...
- zabbix系列(五)zabbix3.0.4 探索主机Discovery自动发现主机详细图文教程
Zabbix 自动发现(Discovery)功能使用 随着监控主机不断增多,有的时候需要添加一批机器,特别是刚用zabbix的运维人员需要将公司的所有服务器添加到zabbix,如果使用传统办法去单个添 ...
- 面向对象编程其实很简单——Python 面向对象(初级篇)
出处:http://www.cnblogs.com/wupeiqi/ 概述 面向过程:根据业务逻辑从上到下写垒代码 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 面向对象:对函 ...
- 在 Win 7或8 下使用 VirtualBOX 虚拟机安装 OS X 10.11 El Capitan 及 Xcode 7.0
注:本文源自于: http://bbs.feng.com/read-htm-tid-9908410.html _____________________________________________ ...
- Deep Learning系统实训之二:梯度下降原理
基本概念理解: 一个epoch:当前所有数据都跑(迭代)了一遍: 那么两个epoch,就是把所有数据跑了两遍,三个epoch就是把所有数据跑了三遍,以此类推. batch_size:每次迭代多少个数据 ...
- 【ES】match_phrase与regexp
刚开始接触es,由于弄不清楚match_phrase和regexp导致很多查询结果与预想的不同.在这整理一下. regexp:针对的是单个词项 match_phrase:针对的是多个词项的相对位置 它 ...