[BZOJ1975]HH去散步 图论+矩阵
[BZOJ1975]HH去散步 图论+矩阵
题目大意
要求出在一个m条边,n个点的图中,相邻两次走的边不能相同,求在t时间时从起点A走到终点B的路径方案总数。将答案mod45989
输入格式:
第一行:五个整数N,M,t,A,B。
后面的m行,每行有两个数\(a_i\) \(b_i\),表示路口\(a_i\) \(b_i\)有有一条边。
输出格式:
一个整数,表示答案。
输入输出样例
input
4 5 3 0 0
0 1
0 2
0 3
2 1
3 2
output
4
Hint
对于30%的数据,N ≤ 4,M ≤ 10,t ≤ 10。 对于100%的数据,N ≤ 20,M ≤ 60,t ≤ 2^30,0 ≤ A,B
解题分析
题目问你路径的方案总数,首先就想到要用矩阵+floyd的算法来求。
我们根据floyd的原理可以知道\(L[i][j]=\sum\limits_{k=1}^{n}L[i][k]*L[k][j]\)
所以我们可以建立一个矩阵 \(g[i][j]\)代表有一条从i到j的比。将这个矩阵幂t次,\(g[i][j]\)就代表i到j的走t条边的方案数。
因为这一题相邻两次走的边不能相同,所以我们就将边变成点来求方案数。
那么怎么统计答案呢?我们可以有一个转移矩阵2m2m,其中\(f[i][j]\)代表第i条边(原图中)的起点与第j条边(原图中)是一个点(且ij不能是同一条边),就代表点(新图)i与点(新图)j是相连的。答案矩阵是一个12m的矩阵,\(ans[1][i]\)代表第i(原图)条边的终点为题目给的A.把ans与自乘t次的F矩阵相乘。然后
$$\sum ans[1][i](i代表终点为B的点(原图的边))$$就是答案。
其实我们可以理解为,ans就是加了一个虚点,代表着一个与所有起点为A的点(原图中的边)相连的点。乘后的ans代表这个虚点到所以点的方案。我们只要统计终点为B的点的方案数就可以了。
代码自带大常数==!
#include <stdio.h>
#include <iostream>
#include <cmath>
#include <queue>
#include <algorithm>
#include <cstring>
#include <climits>
#include <cstdlib>
#define MAXN (60+10)*2
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
using namespace std;
int mod=45989,n,m,a,b,t,num,head[MAXN],tot,tail[MAXN],M;
struct Edge{
int next,to,from,next1;
}edge[MAXN<<1];
void add(int from,int to)
{
edge[++num].next=head[from];
edge[num].next1=tail[to];
edge[num].to=to;
edge[num].from=from;
head[from]=num;
tail[to]=num;
}
struct matrix{
int n,m;
int data[MAXN][MAXN];
void print()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
printf("%d ",data[i][j]);
printf("\n");
}
}
matrix operator * (matrix b)
{
matrix ans;
memset(ans.data,0,sizeof(ans.data));
ans.n=n;ans.m=b.m;
for(int i=1;i<=ans.n;i++)
for(int j=1;j<=ans.m;j++)
for(int k=1;k<=ans.m;k++)
ans.data[i][j]+=(data[i][k]*b.data[k][j])%mod,ans.data[i][j]%=mod;
return ans;
}
void too(matrix b)
{
n=b.n;m=b.m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
data[i][j]=b.data[i][j];
}
}f,ans,zero,pf;
void power(int k)
{
if(k==1) pf=f;
else
{
power(k/2);
if(k%2==1) pf=pf*pf,pf=pf*f;
else pf=pf*pf;
}
}
int main()
{
scanf("%d%d%d%d%d",&n,&m,&t,&a,&b);
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
f.n=f.m=2*m;ans.n=1;ans.m=2*m;M=2*m;
for(int i=head[a];i;i=edge[i].next) ans.data[1][i]=1;
for(int s=0;s<n;s++)
for(int i=head[s];i;i=edge[i].next)
for(int j=head[edge[i].to];j;j=edge[j].next)
if((i+1)!=((j+1)^1))
{
f.data[i][j]++;
}
power(t-1);ans=ans*pf;
for(int i=tail[b];i;i=edge[i].next1)
tot=(tot+ans.data[1][i])%mod;
printf("%d\n",tot);
return 0;
}
[BZOJ1975]HH去散步 图论+矩阵的更多相关文章
- BZOJ_1875_[SDOI2009]HH去散步_矩阵乘法
BZOJ_1875_[SDOI2009]HH去散步_矩阵乘法 Description HH有个一成不变的习惯,喜欢饭后百步走.所谓百步走,就是散步,就是在一定的时间 内,走过一定的距离. 但 是同时H ...
- 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去散步( dp + 矩阵快速幂 )
把双向边拆成2条单向边, 用边来转移...然后矩阵乘法+快速幂优化 ------------------------------------------------------------------ ...
- 【SDOI2009】HH去散步(矩阵快速幂)
题面 题目描述 HH有个一成不变的习惯,喜欢饭后百步走.所谓百步走,就是散步,就是在一定的时间 内,走过一定的距离. 但是同时HH又是个喜欢变化的人,所以他不会立刻沿着刚刚走来的路走回. 又因为HH是 ...
- 1875. [SDOI2009]HH去散步【矩阵乘法】
Description HH有个一成不变的习惯,喜欢饭后百步走.所谓百步走,就是散步,就是在一定的时间 内,走过一定的距离. 但 是同时HH又是个喜欢变化的人,所以他不会立刻沿着刚刚走来的路走回. 又 ...
- [BZOJ 1875] [SDOI 2009] HH去散步【矩阵乘法】
题目链接:BZOJ - 1875 题目分析: 这道题如果去掉“不会立刻沿着刚刚走来的路走回”的限制,直接用邻接矩阵跑矩阵乘法就可以了.然而现在加了这个限制,建图的方式就要做一些改变.如果我们把每一条边 ...
- BZOJ 1875: [SDOI2009]HH去散步(矩阵乘法)
首先,题意就把我们引向了矩阵乘法,注意边长m<=60,那么就按边建图,变成一个120个点的图,然后乱搞就行了。 PS:WA了N久改了3次终于A了QAQ CODE: #include<cst ...
- BZOJ.1875.[SDOI2009]HH去散步(DP 矩阵乘法)
题目链接 比较容易想到用f[i][j]表示走了i步后到达j点的方案数,但是题目要求不能走上一条走过的边 如果这样表示是不好转移的 可以考虑边,f[i][j]表示走了i步后到达第j条边的方案数,那么有 ...
- [SDOI2009]HH去散步 「矩阵乘法计数」
计数问题也许可以转化为矩阵乘法形式 比如若该题没有不能在一条边上重复走的条件限制,那么直接将邻接矩阵转化为矩阵乘法即可 故 矩阵乘法计数 对于计数问题,若可以将 \(n\) 个点表示成 \(n \ti ...
随机推荐
- java书籍推荐:《Java SE 6 技術手册》
Java SE 6 技術手册 或 Java SE 6 技術手册 Java SE 6 技術手册 為什麼選擇用 Markdown?仅仅是單純把文件又一次排版太無聊了,不如趁這個機會學些新東西.所以我就藉 ...
- cocos2d-x 3.0 经常使用对象的创建方式
cocos2d-x 3.0 中全部对象差点儿都能够用create函数来创建,其它的创建方式也是有create函数衍生. 以下来介绍下create函数创建一般对象的方法,省得开发中常常忘记啥的. 1.精 ...
- WPF 基础到企业应用系列2——WPF前世今生
1.开篇前言 非常多时候了解一项新技术的历史和趋势往往比这项技术的本身价值还要重要.WPF作为一项新技术(已经三年多了.或者应该叫老技术了).我们都有必要了解它的来龙去脉,尤其是公司的CT ...
- malloc和new出来的地址都是虚拟地址 你就说内存管理单元怎么可能让你直接操作硬件内存地址!
malloc的实现与物理内存自然是无关的,内核为每个进程维护一张页表,页表存储进程空间内每页的虚拟地址,页表项中有的虚拟内存页对应着某个物理内存页面,也有的虚拟内存页没有实际的物理页面对应.无论mal ...
- ubuntu16.04+caffe训练mnist数据集
1. caffe-master文件夹权限修改 下载的caffe源码编译的caffe-master文件夹貌似没有写入权限,输入以下命令修改: sudo chmod -R 777 ~/caffe-ma ...
- DB-MySQL:MySQL 临时表
ylbtech-DB-MySQL:MySQL 临时表 1.返回顶部 1. MySQL 临时表 MySQL 临时表在我们需要保存一些临时数据时是非常有用的.临时表只在当前连接可见,当关闭连接时,Mysq ...
- 院校-美国:美国国立卫生研究院(NIH)
ylbtech-院校-美国:美国国立卫生研究院(NIH) 美国国立卫生研究院(简称NIH)位于美国马里兰州贝塞斯达(Bethesda),是美国最高水平的医学与行为学研究机构,初创于1887年,任务是探 ...
- dell台式机设置U盘启动步骤
在开机启动看见DELL的标志后,连续按F12键进入BIOS界面,然后按照界面进行操作,操做完成后保存退出,然后再按F12键选择U盘启动. 注意硬盘模式需要选择为disabled.
- PHP单词表
输出语句printechovar_dumpprint_rprintf变量的操作unset预定义变量$_SERVER$_GET$_POST$_REQUEST$_COOKIE,$_SESSION 会话技术 ...
- gcc编译c中有与lua交互的代码
编译C程序中有与Lua有关的程序(编译环境是Linux系统,lua解释器是luajit)gcc -o test30 test30.cpp -I/usr/local/include/luajit-2.0 ...