BZOJ4386[POI2015]Wycieczki——矩阵乘法+倍增
题目描述
给定一张n个点m条边的带权有向图,每条边的边权只可能是1,2,3中的一种。
将所有可能的路径按路径长度排序,请输出第k小的路径的长度,注意路径不一定是简单路径,即可以重复走同一个点。
输入
第一行包含三个整数n,m,k(1<=n<=40,1<=m<=1000,1<=k<=10^18)。
接下来m行,每行三个整数u,v,c(1<=u,v<=n,u不等于v,1<=c<=3),表示从u出发有一条到v的单向边,边长为c。
可能有重边。
输出
包含一行一个正整数,即第k短的路径的长度,如果不存在,输出-1。
样例输入
1 2 1
2 3 2
3 4 2
4 5 1
5 3 1
4 6 3
样例输出
提示
长度为1的路径有1->2,5->3,4->5。
长度为2的路径有2->3,3->4,4->5->3。
长度为3的路径有4->6,1->2->3,3->4->5,5->3->4。
长度为4的路径有5->3->4->5。
因为边权有三种,但边数比较多,因此不能拆边。但点数比较少可以把每个点拆成三个点,同一个点拆成的三个点要连上边,这样就能使边权都是1了。
很容易想到用二分答案来求第k短路径,但这是log2,显然过不去,因此可以预处理出矩阵乘法的2i的矩阵,每次像倍增lca一样如果能走这么多步就走,不能走就尝试2i-1的矩阵的答案数。
那么怎么统计答案?
可以建一个原点(0号点)连向所有拆点后的原图节点,再将原点连向自己,这样第一行每个数就是原点到达对应点步数小于等于矩阵幂次的总路径数。
但这样求的是2i-1步数的答案,因此还要记录每个点的出度,统计时将每个答案乘上对应点的出度即可。
因为k比较大,矩阵乘法过程中会爆longlong,对于两个数加起来爆longlong,那么结果一定是负数,实际结果也就一定大于k,矩乘和求答案时判一下即可。
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<bitset>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
ll a[65][125][125];
ll b[125][125];
ll c[125][125];
int mask;
ll ans;
ll K;
int cnt;
int f[45][3];
int v[121];
int n,m;
int x,y,z;
void multiply(ll a[125][125],ll b[125][125],ll c[125][125])
{
for(int i=0;i<=cnt;i++)
{
for(int j=0;j<=cnt;j++)
{
c[i][j]=0;
for(int k=0;k<=cnt;k++)
{
if(a[i][k]&&b[k][j])
{
if(a[i][k]<0||b[k][j]<0)
{
c[i][j]=-1;
break;
}
if(a[i][k]>K/b[k][j])
{
c[i][j]=-1;
break;
}
c[i][j]+=a[i][k]*b[k][j];
if(c[i][j]<0)
{
c[i][j]=-1;
break;
}
}
}
}
}
}
bool check()
{
ll res=0;
for(int i=0;i<=cnt;i++)
{
if(c[0][i]&&v[i])
{
if(c[0][i]<0)
{
return 0;
}
if(c[0][i]>K/v[i])
{
return 0;
}
res+=c[0][i]*v[i];
if(res<0)
{
return 0;
}
}
}
return res<K;
}
int main()
{
scanf("%d%d%lld",&n,&m,&K);
for(int i=1;i<=n;i++)
{
for(int j=0;j<=2;j++)
{
f[i][j]=++cnt;
}
}
a[0][0][0]++;
for(int i=1;i<=n;i++)
{
for(int j=0;j<=1;j++)
{
a[0][f[i][j]][f[i][j+1]]++;
}
a[0][0][f[i][0]]++;
}
while(m--)
{
scanf("%d%d%d",&x,&y,&z);
a[0][f[x][z-1]][f[y][0]]++;
v[f[x][z-1]]++;
}
for(mask=0;(1ll<<mask)<=K*3;mask++);
mask--;
for(int i=1;i<=mask;i++)
{
multiply(a[i-1],a[i-1],a[i]);
}
for(int i=0;i<=cnt;i++)
{
b[i][i]=1;
}
for(int i=mask;i>=0;i--)
{
multiply(b,a[i],c);
if(check())
{
ans|=1ll<<i;
for(int j=0;j<=cnt;j++)
{
for(int k=0;k<=cnt;k++)
{
b[j][k]=c[j][k];
}
}
}
}
ans++;
if(ans>K*3)
{
ans=-1;
}
printf("%lld",ans);
}
BZOJ4386[POI2015]Wycieczki——矩阵乘法+倍增的更多相关文章
- 【bzoj4386】[POI2015]Wycieczki 矩阵乘法
题目描述 给定一张n个点m条边的带权有向图,每条边的边权只可能是1,2,3中的一种.将所有可能的路径按路径长度排序,请输出第k小的路径的长度,注意路径不一定是简单路径,即可以重复走同一个点. 输入 第 ...
- BZOJ4386 [POI2015]Wycieczki 矩阵+倍增
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4386 题解 一眼就可以看出来是邻接矩阵快速幂. 可是这里的边权不为 \(1\).不过可以发现, ...
- BZOJ 4386 Luogu P3597 [POI2015]Wycieczki (矩阵乘法)
题目链接: (bzoj) https://www.lydsy.com/JudgeOnline/problem.php?id=4386 (luogu) https://www.luogu.org/pro ...
- CF_576D_Flights for Regular Customers_矩阵乘法+倍增floyd+bitset+bfs
CF_576D_Flights for Regular Customers_矩阵乘法+倍增floyd+bitset https://www.luogu.org/problemnew/show/CF57 ...
- BZOJ4386 : [POI2015]Wycieczki
将每个点拆成三个点,并将转移转化为矩阵乘法,然后倍增即可求出第$k$短路的长度,注意对爆long long情况的处理. 时间复杂度$O(n^3\log k)$. #include<cstdio& ...
- bzoj 2165: 大楼【Floyd+矩阵乘法+倍增+贪心】
1<<i的结果需要是long long的话i是long long是没用的--要写成1ll<<i--我别是个傻子吧 虽然写的是二进制贪心,但是我觉得二分可能更好写吧(但是会慢) ...
- BZOJ4386[POI2015]Wycieczki / Luogu3597[POI2015]WYC - 矩乘
Solution 想到边权为$1$的情况直接矩乘就可以得出长度$<=t$ 的路径条数, 然后二分check一下即可 但是拓展到边权为$2$,$3$ 时, 需要新建节点 $i+n$ 和 $i+2n ...
- 【BZOJ-4386】Wycieczki DP + 矩阵乘法
4386: [POI2015]Wycieczki Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 197 Solved: 49[Submit][Sta ...
- CF781D Axel and Marston in Bitland [倍增 矩阵乘法 bitset]
Axel and Marston in Bitland 好开心第一次补$F$题虽然是$Div.2$ 题意: 一个有向图,每条边是$0$或$1$,要求按如下规则构造一个序列然后走: 第一个是$0$,每次 ...
随机推荐
- 【Codeforces 111C】Petya and Spiders
Codeforces 111 C 题意:给\(n\times m\)的网格,每个点上有一个蜘蛛,每个蜘蛛可以向上.下.左.右走一步或者不动,问最多能存在多少没有蜘蛛的点. 思路1: 首先因为\(n\) ...
- Luogu P2661 [NOIP2015] 信息传递
qwq 今天做完并查集突然想起来这道以前做的好(shui)题, 虽然是黄题,但是是并查集一个比较特别的用法 这道题大概可以用求最小环的方式来做,但是从直觉上果然还是并查集w 乍一看只要求出“父→子”即 ...
- 网易云音乐 歌词制作软件 BesLyric (最新版本下载)
导读 BesLyric , 一款专门制作 网易云音乐 LRC 滚动歌词的软件! 搜索.下载.制作 歌词更方便! 哈哈,喜欢网易云音乐,又愁于制作歌词的童鞋有福啦!Beslyric 为你排忧解难! 本文 ...
- 开发板测试-GPRS
注意事项: 经过测试,为了使STM32和Air202的串口稳定通信,需要更改 以前电路感觉应该是三极管控制极4.7K电阻太大,又因为开关速度快,然后开关的时候导致不足以让三极管处于全部导通状态,所以电 ...
- 5、数组&字符串&结构体&共用体&枚举
程序中内存从哪里来 三种内存来源:栈(stack).堆(heap).数据区(.date): 栈(stack) 运行自动分配.自动回收,不需要程序员手工干预: 栈内存可以反复使用: 栈反复使用后,程序不 ...
- sprintf()函数用法
sprintf()用法见操作手册:http://www.php.net/sprintf 简单写下format的用法: 1. + - 符号,数字 2. 填充字符 默认是空格,可以是0.如果其他字符填充, ...
- Java8中的HashMap分析
本篇文章是网上多篇文章的精华的总结,结合自己看源代码的一些感悟,其中线程安全性和性能测试部分并未做实践测试,直接是“拿来”网上的博客的. 哈希表概述 哈希表本质上一个数组,数组中每一个元素称为一个箱子 ...
- 【转】ORA-00257:archiver error. 错误的处理方法
出现这个问题的原因一般是日志满了.这里以用户tt为例: 一.用sys用户登录 sqlplus sys/pass@tt as sysdba 二.看看archiv log所在位置 SQL> show ...
- BootStrap学习(6)_模态框
一.模态框 模态框(Modal)是覆盖在父窗体上的子窗体.通常,目的是显示来自一个单独的源的内容,可以在不离开父窗体的情况下有一些互动.子窗体可提供信息.交互等. 如果只使用该功能,只引入BootSt ...
- WordPress更新提示无法创建目录的解决方案
上一篇我们说到无法连接FTP服务器,我们已经完美的解决了,然后...发现...还是无法更新,啥情况??? 提示为无法创建目录 原因是执行更新程序的是www用户, 解决方案如下: 需要把插件或主程序下载 ...