Codeforces 576D - Flights for Regular Customers(bitset 优化广义矩阵乘法)
题意:
有一张 \(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 优化广义矩阵乘法)的更多相关文章
- Codeforces 576D Flights for Regular Customers(矩阵加速DP)
题目链接 Flights for Regular Customers 首先按照$d$的大小升序排序 然后分成$m$个时刻,每条路径一次处理过来. $can[i][j]$表示当前时刻$i$能否走到$j ...
- Codeforces 576D Flights for Regular Customers (图论、矩阵乘法、Bitset)
题目链接 http://codeforces.com/contest/576/problem/D 题解 把边按\(t_i\)从小到大排序后枚举\(i\), 求出按前\((i-1)\)条边走\(t_i\ ...
- Codeforces 576D. Flights for Regular Customers(倍增floyd+bitset)
这破题调了我一天...错了一大堆细节T T 首先显然可以将边权先排序,然后逐个加进图中. 加进图后,倍增跑跑看能不能到达n,不能的话加新的边继续跑. 倍增的时候要预处理出h[i]表示转移矩阵的2^0~ ...
- Codeforces 576D Flights for Regular Customers 矩阵快速幂+DP
题意: 给一个$n$点$m$边的连通图 每个边有一个权值$d$ 当且仅当当前走过的步数$\ge d$时 才可以走这条边 问从节点$1$到节点$n$的最短路 好神的一道题 直接写做法喽 首先我们对边按$ ...
- (中等) 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 ...
- 576D Flights for Regular Customers
分析 https://www.cnblogs.com/onioncyc/p/8037056.html 写的好像有点问题 但是大致就是这个意思 代码很好理解 代码 #include<bits/st ...
- CF576D Flights for Regular Customers 矩阵乘法 + Bitset优化
%%%cxhscst2's blog Codeforces 576D Flights for Regular Customers(矩阵加速DP) 代码非常优美 + 简洁,学习到了 Code: #inc ...
- 【CodeForces】576 D. Flights for Regular Customers
[题目]D. Flights for Regular Customers [题意]给定n个点m条边的有向图,每条边有di表示在经过该边前必须先经过di条边,边可重复经过,求1到n的最小经过边数.n,m ...
- 「CF576D」 Flights for Regular Customers
「CF576D」 Flights for Regular Customers 对不起我又想网络流去了 你看这长得多像啊,走过至少多少条边就是流量下界,然后没上界 但是这个题求的最少走多少条边啊...完 ...
随机推荐
- linux系统(centos)下su和sudo命令的区别
linux系统(centos)下su和sudo命令的区别 区别 我们在日常使用过程中,这2个命令很多时候能达到相同的效果,对细节区别十分模糊,这里进行简单的解释和区分.希望大家能够正确使用这2个命令, ...
- kivy 选择框
from kivy.app import App from kivy.uix.boxlayout import BoxLayout from kivy.lang import builder # 注册 ...
- UltraSoft - Beta - Scrum Meeting 2
Date: May 18th, 2020. Scrum 情况汇报 进度情况 组员 负责 今日进度 q2l PM.后端 建立Beta仓库管理增加服务器部署和Git协作文档 Liuzh 前端 查阅响应式布 ...
- Spring父子上下文的使用案例
Spring父子上下文的使用案例 一.背景 二.需求 三.实现步骤 1.基础代码编写 2.测试结果 四.小彩蛋 五.完整代码 一.背景 最近在看在使用Spring Cloud的时候发现,当我们通过Fe ...
- 修炼Servlet
修炼Servlet 一.Servlet简单认识 1.Servlet是什么 Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的 ...
- 从零开始 DIY 智能家居 - 基于 ESP32 的智能语音合成播报模块
目录 前言 硬件选择 代码解析 获取代码 设备控制命令: 设备和协议初始化流程: 配置设备信息 回调函数注册 语音播报与设置流程 总结 前言 这里这么多设备,突然发现我做的好像都是传感器之类的居多好像 ...
- 构建乘积数组 牛客网 剑指Offer
构建成绩数组 牛客网 剑指Offer 题目描述 给定一个数组A[0,1,...,n-1],请构建一个数组B[0,1,...,n-1],其中B中的元素B[i]=A[0]A[1]...*A[i-1]A[i ...
- AGC036 A-Triangle | 构造
题目链接 题意: 给出一个数$S(1\leqslant S \leqslant 10^{18})$. 要求在平面直角坐标系中找到三个点$(X_1,Y_1),(X_2,Y_2),(X_3,Y_3)$,满 ...
- poj 3041 Asteroids(最小点覆盖)
题意: N*N的矩阵,有K个敌人,坐标分别是(C1,C1),.....,(Rk,Ck). 有一个武器,每发射一次,可消掉某行或某列上的所有的敌人. 问消灭所有敌人最少需要多少发. 思路: 二分建图:左 ...
- linux系列之: 你知道查看文件空间的两种方法吗?
目录 简介 du命令 df命令 总结 简介 linux系统中查看文件空间大小应该是一个非常常见的命令了,今天给大家介绍linux系统中查看文件空间的两种方法和在使用中可能会遇到的奇怪问题. 为什么会有 ...