题面传送门

题意:

有一张 \(n\) 个点 \(m\) 条边的有向图,你初始在 \(1\) 号点,边上有边权 \(c_i\) 表示只有当你经过至少 \(c_i\) 条边的时候你才能经过第 \(i\) 条边。

求从 \(1\) 号点开始最少走过多少条边才能到达 \(n\) 号点。

\(n,m \leq 150,c_i\leq 10^9\)

注意到题目中 \(c_i\) 的数据范围可以达到 \(10^9\),我们显然不能一步步枚举可达的位置。

但是 \(m\) 的数据范围很小,说明转移矩阵最多改变 \(150\) 次,这启示我们可以用矩阵乘法

具体来说,我们建立 \(1\times n\) 的矩阵 \(A\),\(A_i\) 表示在当前状态下 \(i\) 是否能够到达(\(0/1\))。

再建立一个 \(n\times n\) 的转移矩阵 \(B\),\(B_{i,j}\) 表示 \(i\) 与 \(j\) 是否有边相连。

那么走一步之后,新的 \(A'_i=\or_{i=1}^nA_k\and B_{k,i}\)

也就是说,如果存在一个点 \(k\) 使得在当前状态下能够到达 \(k\) 并且 \(k\) 与 \(i\) 有直接边相连,那么就可以从 \(k\) 走到 \(i\)。

由于广义矩阵乘法也满足乘法结合律,那么走 \(t\) 步后可达状态为 \(A\times B^t\)

考虑将边按照 \(c_i\) 从小到大排序,然后依次改变转移矩阵 \(B\)

然后做一遍多源 \(bfs\),求出可达的所有点中,到达点 \(n\) 的最短距离。

时间复杂度 \(\mathcal O(n^3m\log c_i)\)。注意到矩阵 \(A,B\) 每一位都是 \(0\) 或 \(1\),矩阵乘法中也只包含位运算,因此可以使用 bitset 优化,时间复杂度 \(\mathcal O(\frac{n^3m\log c_i}{\omega})\) 。

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fz(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define ffe(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define mp make_pair
typedef pair<int,int> pii;
typedef long long ll;
const int MAXN=150+5;
const int MAXM=150+5;
int n,m,d[MAXN];
struct edge{
int u,v,c;
friend bool operator <(edge a,edge b){
return a.c<b.c;
}
} e[MAXM];
struct mat{
bitset<MAXN> x[MAXN];
friend mat operator *(mat a,mat b){
mat c;
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++)
if(a.x[i][j]) c.x[i]|=b.x[j];//optimize multiplation by bitset
return c;
}
} to,c;
mat qpow(mat x,int e){
mat ret;for(int i=1;i<=n;i++) ret.x[i][i]=1;
while(e){if(e&1) ret=ret*x;x=x*x;e>>=1;}return ret;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++) scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].c);
sort(e+1,e+m+1);to.x[1][1]=1;int pre=0,ans=2e9;
for(int i=1;i<=m;i++){
to=to*qpow(c,e[i].c-pre);
pre=e[i].c;c.x[e[i].u][e[i].v]=1;
memset(d,63,sizeof(d));
queue<int> q;for(int j=1;j<=n;j++) if(to.x[1][j]) q.push(j),d[j]=0;
while(!q.empty()){
int cur=q.front();q.pop();
for(int j=1;j<=n;j++) if(c.x[cur][j]&&d[j]>1e9){
d[j]=d[cur]+1;q.push(j);
}
}
if(d[n]<1e9) ans=min(ans,e[i].c+d[n]);
}
if(ans==2e9) puts("Impossible");
else printf("%d\n",ans);
return 0;
}

Codeforces 576D - Flights for Regular Customers(bitset 优化广义矩阵乘法)的更多相关文章

  1. Codeforces 576D Flights for Regular Customers(矩阵加速DP)

    题目链接  Flights for Regular Customers 首先按照$d$的大小升序排序 然后分成$m$个时刻,每条路径一次处理过来. $can[i][j]$表示当前时刻$i$能否走到$j ...

  2. Codeforces 576D Flights for Regular Customers (图论、矩阵乘法、Bitset)

    题目链接 http://codeforces.com/contest/576/problem/D 题解 把边按\(t_i\)从小到大排序后枚举\(i\), 求出按前\((i-1)\)条边走\(t_i\ ...

  3. Codeforces 576D. Flights for Regular Customers(倍增floyd+bitset)

    这破题调了我一天...错了一大堆细节T T 首先显然可以将边权先排序,然后逐个加进图中. 加进图后,倍增跑跑看能不能到达n,不能的话加新的边继续跑. 倍增的时候要预处理出h[i]表示转移矩阵的2^0~ ...

  4. Codeforces 576D Flights for Regular Customers 矩阵快速幂+DP

    题意: 给一个$n$点$m$边的连通图 每个边有一个权值$d$ 当且仅当当前走过的步数$\ge d$时 才可以走这条边 问从节点$1$到节点$n$的最短路 好神的一道题 直接写做法喽 首先我们对边按$ ...

  5. (中等) CF 576D Flights for Regular Customers (#319 Div1 D题),矩阵快速幂。

    In the country there are exactly n cities numbered with positive integers from 1 to n. In each city ...

  6. 576D Flights for Regular Customers

    分析 https://www.cnblogs.com/onioncyc/p/8037056.html 写的好像有点问题 但是大致就是这个意思 代码很好理解 代码 #include<bits/st ...

  7. CF576D Flights for Regular Customers 矩阵乘法 + Bitset优化

    %%%cxhscst2's blog Codeforces 576D Flights for Regular Customers(矩阵加速DP) 代码非常优美 + 简洁,学习到了 Code: #inc ...

  8. 【CodeForces】576 D. Flights for Regular Customers

    [题目]D. Flights for Regular Customers [题意]给定n个点m条边的有向图,每条边有di表示在经过该边前必须先经过di条边,边可重复经过,求1到n的最小经过边数.n,m ...

  9. 「CF576D」 Flights for Regular Customers

    「CF576D」 Flights for Regular Customers 对不起我又想网络流去了 你看这长得多像啊,走过至少多少条边就是流量下界,然后没上界 但是这个题求的最少走多少条边啊...完 ...

随机推荐

  1. 笨方法学python中执行argv提示ValueError: not enough values to unpack (expected 4, got 1)

    解决方法:选择Terminal中输入执行ex13.py 1 2 3 执行结果如下图

  2. python字符串调用举例

    以如下打印为例: my name is tom and my age is 12 方式一:字符串格式化表达式 name = 'tom' age = 12 print("my name is ...

  3. Java:TreeMap类小记

    Java:TreeMap类小记 对 Java 中的 TreeMap类,做一个微不足道的小小小小记 概述 前言:之前已经小小分析了一波 HashMap类.HashTable类.ConcurrentHas ...

  4. 彻底搞通TCP滑动窗口

    在我们当初学习网络编程的时候,都接触过TCP,在TCP中,对于数据传输有各种策略,比如滑动窗口.拥塞窗口机制,又比如慢启动.快速恢复.拥塞避免等.通过本文,我们将了解滑动窗口在TCP中是如何使用的. ...

  5. sql 多表联合查询更新

    sqlserver: update A a set a.i = b.k from B b where a.key = b.key oracle : update A a set a.i = (sele ...

  6. evaluate-reverse-polist-notation leetcode C++

    Evaluate the value of an arithmetic expression in Reverse Polish Notation. Valid operators are+,-,*, ...

  7. Typecho部署小破站

    写在前面 以前利用 Github Page + Hexo框架 + Next主题搭建过静态博客,没错就是那个黑白色系的网页!但是体验并不是很好,一来本身是静态网页,页面内容要修改都需要在本地修改完上传到 ...

  8. idea如何在终端使用git并解决终端中文乱码

    idea使用git终端 在idea设置中 找到Settings-Tools-Terminal-Shell path,替换为git安装目录下的bin/bash.exe 解决中文乱码 在git安装目录下找 ...

  9. SpringCould | Nacos与Feign

    服务注册Nacos 介绍 概念 一个更易于构建云原生应用的动态服务发现.配置管理和服务管理平台. Nacos: Dynamic Naming and Configuration Service Nac ...

  10. psutil模块详解

    import psutil#1.系统性能信息模块psutilmem = psutil.virtual_memory()print(mem)#svmem(total=8442675200, availa ...