Codeforces 576D Flights for Regular Customers 矩阵快速幂 (看题解)

Flights for Regular Customers

 临接矩阵的 k 次 就是 恰好 走 k 步从 i 走到 j 的方案数, 方案数在这里并不关键, 所以可以把它变成01矩阵。

一个很直观的想法是用二分取check它, 但是这并不单调。。 然后就不会了。。 

我们可以把G[ n - 1] [ n - 1 ] 变成  1 , 这个函数就变成单调了, 然后直接二分check就好了, 可以用bitset优化一下, 不优化其实也能过。

还有一种方法就是, 每新加入一条边, 我们暴力跑一遍图取check就好啦。

#include<bits/stdc++.h>
#define LL long long
#define LD long double
#define ull unsigned long long
#define fi first
#define se second
#define mk make_pair
#define PLL pair<LL, LL>
#define PLI pair<LL, int>
#define PII pair<int, int>
#define SZ(x) ((int)x.size())
#define ALL(x) (x).begin(), (x).end()
#define fio ios::sync_with_stdio(false); cin.tie(0);

using namespace std;

const int N = 150 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-8;
const double PI = acos(-1);

template<class T, class S> inline void add(T& a, S b) {a += b; if(a >= mod) a -= mod;}
template<class T, class S> inline void sub(T& a, S b) {a -= b; if(a < 0) a += mod;}
template<class T, class S> inline bool chkmax(T& a, S b) {return a < b ? a = b, true : false;}
template<class T, class S> inline bool chkmin(T& a, S b) {return a > b ? a = b, true : false;}

const int MN = 150;

struct Matrix {
    bitset<MN> a[MN];
    void init() {
        for(int i = 0; i < MN; i++)
            a[i][i] = 1;
    }
    void setVal(int c[MN][MN]) {
        for(int i = 0; i < MN; i++)
            for(int j = 0; j < MN; j++)
                a[i][j] = c[i][j];
    }
    Matrix operator * (const Matrix& B) const {
        Matrix C;
        for(int i = 0; i < MN; i++)
            for(int j = 0; j < MN; j++)
                if(a[i][j]) C.a[i] |= B.a[j];
        return C;
    }
    Matrix operator ^ (LL b) {
        Matrix C; C.init();
        Matrix A = *this;
        while(b) {
            if(b & 1) C = C * A;
            A = A * A; b >>= 1;
        }
        return C;
    }
} mat[N], now[N], tmp;

int n, m, a[N], b[N], d[N];
int G[MN][MN];
vector<int> oo;
vector<PII> edge[N];

int main() {
    scanf("%d%d", &n, &m);
    for(int i = 0; i < m; i++) {
        scanf("%d%d%d", &a[i], &b[i], &d[i]);
        a[i]--; b[i]--;
        oo.push_back(d[i]);
    }
    oo.push_back(0);
    sort(ALL(oo));
    oo.erase(unique(ALL(oo)), oo.end());
    for(int i = 0; i < m; i++) {
        edge[lower_bound(ALL(oo), d[i]) - oo.begin()].push_back(mk(a[i], b[i]));
    }
    tmp.init();
    int p = SZ(oo) - 1;
    G[n - 1][n - 1] = 1;
    for(int i = 0; i < SZ(oo); i++) {
        now[i] = tmp;
        if(now[i].a[0][n - 1]) {
            p = i - 1;
            break;
        }
        for(auto& e : edge[i]) {
            G[e.fi][e.se] = 1;
        }
        mat[i].setVal(G);
        if(i == SZ(oo) - 1) break;
        tmp = tmp * (mat[i] ^ (oo[i + 1] - oo[i]));
    }
    Matrix gg;
    int low = 1, high = p == SZ(oo) - 1 ? 1000000200 : oo[p + 1] - oo[p], mid, step = -1;
    while(low <= high) {
        mid = low + high >> 1;
        gg = now[p] * (mat[p] ^ mid);
        if(gg.a[0][n - 1]) high = mid - 1, step = mid;
        else low = mid + 1;
    }
    if(~step) printf("%d
", oo[p] + step);
    else puts("Impossible");
    return 0;
}

/*
*/
原文地址:https://www.cnblogs.com/CJLHY/p/10818940.html