Codeforces 576D Flights for Regular Customers Matrix Fast Power + DP

The meaning of the title:
give \(n\) a \(n\) point \(m\) edge connected graph, each edge has a weight \(d\) if and only if the current number of steps \(\ ge d\) can take this edge to ask the shortest path from node \(1\) to node \(n\)

How to write a question of the good god directly

First, we sort the edges according to \(d_i\) from small to large, and set \(f_i\) to represent the connection between all points after adding \(1\sim i-1\) to all edges \(d_i\) times The case \(G\) represents an adjacency matrix that only connects the edges of \(1\sim i-1\) . These we can use a \(01\) adjacency matrix to store, then there are

\(f_i=f_{i-1}*G^{d_i-d_{i-1}}\)

This is obviously a process of fast exponentiation of the matrix

After that, it is only necessary to judge whether the connection between \(1\) and \(n\) is not connected, and then continue to judge the next edge, otherwise it will be judged in the current range.

This kind of complexity is still not good enough. We found that the process of matrix multiplication can be pressed and done later, so the state of a matrix is ​​pressed into \(n\) \(lowbit<n>\) This is enough

My code is not pressed, but directly multiplied by violence, but after a little optimization, it passed~

#include<bits/stdc++.h>
using namespace std;
#define FO(x) {freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);}
#define pa pair<int,int>
#define mod 1000000007
#define ll long long
#define mk make_pair
#define pb push_back
#define fi fisrt
#define se second
#define cl(x) memset(x,0,sizeof x)
#ifdef Devil_Gary
#define bug(x) cout<<(#x)<<" "<<(x)<<endl
#define debug(...) fprintf(stderr, __VA_ARGS__)
#else
#define bug(x)
#define debug(...)
#endif
const int INF = 0x7fffffff;
const int N=155;
/*
char *TT,*mo,but[(1<<15)+2];
#define getchar() ((TT==mo&&(mo=(TT=but)+fread(but,1,1<<15,stdin),TT==mo))?-1:*TT++)//*/
inline int read(){
    int x=0,rev=0,ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')rev=1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return rev?-x:x;
}
struct data{
    int u,v,t;
    bool operator < (const data&ch){
        return t<ch.t;
    }
}e[N]; 
int cnt,n,m,tmp[N],sz,bin[32]={1};
struct matrix{
    bool v[N][N];
    matrix operator * (const matrix&b){
        matrix c;cl(c.v);
        for(int j=1;j<=n;j++)
            for(int i=1;i<=n;i++){
                if(!v[j][i]) continue;
                for(int k=1;k<=n;k++)
                    c.v[j][k]|=v[j][i]&&b.v[i][k];
            }
        return c;
    }
}g[N],G,f[N][32];
bool judge(int x){
    int pos=upper_bound(tmp+1,tmp+sz+1,x)-tmp-1,ret=x-tmp[pos];
//  debug("x=%d pos=%d\n",x,pos);
    matrix d=g[pos];
//  bug(d.v[1][n]);
    for(int k=0;k<=30;k++){
        if(bin[k]&ret){
            d=d*f[pos][k];
        }
    }
    return d.v[1][n];
}
int main(){
#ifdef Devil_Gary
    freopen("in.txt","r",stdin);
#endif
    n=read(),m=read();
    for(int i=1;i<=30;i++) bin[i]=bin[i-1]<<1;
    for(int i=1;i<=n;i++) g[1].v[i][i]=1;
    for(int i=1;i<=m;i++){
        e[++cnt].u=read(),e[cnt].v=read(),e[i].t=read();
//      if(!e[i].t) g[1].v[e[i].u][e[i].v]=1;
        tmp[++sz]=e[i].t;
    } 
    e[++cnt].u=n,e[cnt].v=n,e[cnt].t=0,tmp[++sz]=0;
    sort(tmp+1,tmp+sz+1); 
    sz=unique(tmp+1,tmp+sz+1)-tmp-1;
    sort(e+1,e+cnt+1);
    for(int i=1,j=1;i<=sz;i++){
        for(;e[j].t<=tmp[i]&&j<=cnt;j++){
            G.v[e[j].u][e[j].v]=1;
        }
        f[i][0]=G;
        for(int k=1;k<=30;k++) f[i][k]=f[i][k-1]*f[i][k-1];
        if(i==sz) continue;
        int ret=tmp[i+1]-tmp[i];
        g[i+1]=g[i]; 
        for(int k=0;k<=30;k++){
            if(bin[k]&ret){
                g[i+1]=g[i+1]*f[i][k]; 
            }
        } 
    }
    int l=0,r=1e9+155;
    while(l<r){
        int mid=l+r>>1;
        if(judge(mid)) r=mid;
        else l=mid+1; 
    }
/*  debug("l=%d rr=%d\n",l,tmp[sz]+n+1);*/
    if(l==1e9+155) return puts("Impossible"),0;
    return !printf("%d\n",l); 
}

The following is the method of pressingI glued it directly

#include <bits/stdc++.h>
using namespace std;
int n, m;
const int N = 160;
struct edge
{
    int a, b, c;
} E[N];
struct mat
{
    bitset <N> d[N];
} O, I, P, Q;
int comp(edge x, edge y)
{
    return x.c < y.c;
}
mat operator * (mat a, mat b)
{
    mat c;
    for (int i = 1; i <= n; ++ i)
        for (int j = 1; j <= n; ++ j)
            if (a.d[i][j])
                c.d[i] |= b.d[j];
    return c;
}
mat operator ^ (mat a, int b)
{
    mat c = I;
    for (; b; b >>= 1, a = a * a)
        if (b & 1) c = c * a;
    return c;
}
void print(mat a)
{
    for (int i = 1; i <= n; ++ i)
    {
        for (int j = 1; j <= n; ++ j)
            cerr << a.d[i][j] << " ";
        cerr << endl;
    }
}
int res;
int main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; ++ i)
        I.d[i][i] = 1;
    for (int i = 1; i <= m; ++ i)
        cin >> E[i].a >> E[i].b >> E[i].c;
    sort(E + 1, E + m + 1, comp);
    E[m + 1].c = E[m].c + n + 5;
    P = I; Q.d[n][n] = 1;
    for (int i = 1; i <= m + 1; ++ i)
    {
        cout<<i<<endl; 
        mat tmp = P * (Q ^ (E[i].c - E[i - 1].c));
        if (!tmp.d[1][n])
        {
            Q.d[E[i].a][E[i].b] = 1;
            P = tmp;
            continue;
        }
        res = E[i - 1].c;
        while (!P.d[1][n]) P = P * Q, res ++;
        cout << res << endl;
        return 0;
    }
    cout << "Impossible" << endl;
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324998307&siteId=291194637