CF576D Flights for Regular Customers【2019集训队作业】
CF576D Flights for Regular Customers
首先因为只有 n n n 个点,所以最多只有 n n n 个不同的 d d d 。
我们对每一个 d d d 从小到大来求出走 d − 1 d-1 d−1 步能到达哪些点。
因为我们的 d d d 是从小到大来求的,所以对于单个 d d d 可以简单递推。
递推的过程可以用矩阵+ bitset 来加速。
#include <bits/stdc++.h>
#define N 152
#define bit bitset<N>
using namespace std;
struct edge{
int u, v, c;
bool operator < (edge x){
return c < x.c;
}
}e[N];
int n, m;
int dis[N];
bit tmp[N], mat[N];
void mul(bit *x, bit *y, bit *z){
bit p[N];
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= n; ++j)
if(y[i][j]) p[i] |= z[j];
for(int i = 1; i <= n; ++i) x[i] = p[i];
return ;
}
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 + 1 + m); mat[1][1] = 1;
if(e[1].c != 0) return puts("Impossible"), 0;
for(int now = 1; now <= m;){
int pos = now; bit p[N];
while(e[now].c == e[pos].c && pos <= m)
tmp[e[pos].u][e[pos].v] = 1, ++pos;
for(int i = 1; i <= n; ++i) p[i] = tmp[i];
queue<int> Q; memset(dis, -1, sizeof dis);
for(int i = mat[1]._Find_first(); i <= n; i = mat[1]._Find_next(i))
Q.push(i), dis[i] = 0;
while(!Q.empty()){
int u = Q.front(); Q.pop();
for(int i = 1; i <= n; ++i)
if(tmp[u][i] && dis[i] == -1)
dis[i] = dis[u] + 1, Q.push(i);
}
if(dis[n] != -1) return printf("%d\n", e[now].c + dis[n]), 0;
int y = max(0, e[pos].c - e[now].c);
while(y){
if(y & 1) mul(mat, mat, p);
mul(p, p, p); y >>= 1;
} now = pos;
}
puts("Impossible");
return 0;
}