1. 程式人生 > >Bzoj5109: [CodePlus 2017]大吉大利,晚上吃雞!

Bzoj5109: [CodePlus 2017]大吉大利,晚上吃雞!

check class strong vector pre != truct count() href

題面

傳送門

Sol

先正反兩遍\(Dijsktra\)算出經過某個點的\(S\)\(T\)的最短路條數\(F\)

滿足條件一就是要滿足\(F(A)+F(B)=F(T)\)

條件二

標算比較簡單

直接\(bitset\)存儲不能到達它的和它不能到的點

然後開\(map\)把所有相同的\(F(B)\)變成\(bitset\)

然後每次枚舉\(A\),就直接查表然後用\(bitset\)裏的\(count\)就好了

註意如果\(ST\)不連通輸出\(C_n^2\)

空間\(1GB\)就可以過

註意!!!

\(AC\)的同誌不要以為真的\(AC\)了!!!
數據真的水
\(S\)\(T\)的路徑條數不會大於\(1\)


然後我自己亂打一個,樣例都沒過就\(AC\)

標算代碼

# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
const int _(50005);
typedef long long ll;

IL int Input(){
    RG int x = 0, z = 1; RG char c = getchar();
    for(; c < '0' || c > '9'
; c = getchar()) z = c == '-' ? -1 : 1; for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48); return x * z; } int n, m, cnt, S, T, first[_], d[_], vis[_]; struct Edge{ int to, next, w; } edge[_ << 1]; ll dis[2
][_], f[2][_], F[_], ans; struct Point{ int u; ll d; IL int operator <(RG Point B) const{ return d > B.d; } }; priority_queue <Point> Q; queue <int> Que; bitset <50000> G[2][_]; map <ll, bitset <50000> > M; IL void Add_Graph(RG int u, RG int v, RG int w){ edge[cnt] = (Edge){v, first[u], w}, first[u] = cnt++; } IL void Dijkstra(RG int op){ for(RG int i = 1; i <= n; ++i) dis[op][i] = (ll)1e18, vis[i] = 0; if(!op) f[op][S] = 1, dis[op][S] = 0, Q.push((Point){S, 0}); else f[op][T] = 1, dis[op][T] = 0, Q.push((Point){T, 0}); while(!Q.empty()){ RG Point x = Q.top(); Q.pop(); if(vis[x.u]) continue; vis[x.u] = 1; for(RG int e = first[x.u]; e != -1; e = edge[e].next){ RG int v = edge[e].to, w = edge[e].w; if(x.d + w < dis[op][v]){ dis[op][v] = x.d + w, f[op][v] = f[op][x.u]; Q.push((Point){v, x.d + w}); } else if(x.d + w == dis[op][v]) f[op][v] += f[op][x.u]; } } } IL int Check(RG int x, RG ll w, RG int y, RG int op){ return dis[op][x] + w + dis[!op][y] == dis[0][T]; } IL void TopSort(RG int op){ for(RG int i = 1; i <= n; ++i) for(RG int e = first[i]; e != -1; e = edge[e].next){ RG int v = edge[e].to, w = edge[e].w; if(Check(i, w, v, op)) ++d[v]; } for(RG int i = 1; i <= n; ++i) if(!d[i]) Que.push(i); while(!Que.empty()){ RG int u = Que.front(); Que.pop(); for(RG int e = first[u]; e != -1; e = edge[e].next){ RG int v = edge[e].to, w = edge[e].w; if(!Check(u, w, v, op)) continue; G[op][v] &= G[op][u]; if(!--d[v]) Que.push(v); } } } int main(RG int argc, RG char* argv[]){ Fill(first, -1), n = Input(), m = Input(), S = Input(), T = Input(); for(RG int i = 1; i <= m; ++i){ RG int u = Input(), v = Input(), w = Input(); Add_Graph(u, v, w), Add_Graph(v, u, w); } Dijkstra(0); if(!f[0][T]) return printf("%lld\n", 1LL * n * (n - 1) >> 1), 0; Dijkstra(1); for(RG int i = 1; i <= n; ++i){ G[0][i].set(), G[1][i].set(); G[0][i][0] = G[0][i][i] = G[1][i][0] = G[1][i][i] = 0; } TopSort(0), TopSort(1); for(RG int i = 1; i <= n; ++i) if(dis[0][i] + dis[1][i] == dis[0][T]) F[i] = f[0][i] * f[1][i]; for(RG int i = 1; i <= n; ++i) M[F[i]].set(i); for(RG int i = 1; i <= n; ++i) ans += (M[F[T] - F[i]] & G[0][i] & G[1][i]).count(); return printf("%lld\n", ans >> 1), 0; }

然而Bzoj的空間變成了512MB

TAT

然後還可以這樣做

首先可以枚舉一條最短路上的點\(i\)

然後枚舉不在這條最短路上的點再來統計答案

把最短路弄出來到一個數組中

然後不在這條路上的點的合法的\(i\)是這個數組的下標的區間\([l, r]\)

然後可以正反兩邊拓撲排序求出這個區間

為什麽是一個區間

首先前提是這個點走到\(j\),然後\(j\)\(T\)是最短路

  • 如果\(j\)能走到這個點,那麽\(j\)的所有前驅都能到這個點

  • 如果這個點能走到\(j\),那麽這個點也能走到\(j\)的所有後繼

然後枚舉最短路上的點,每次到\(i\)時,就把左端點是\(i\)的加進\(map\)

然後把右端點是\(i\)的從\(map\)中減掉

# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
const int _(50005);
typedef long long ll;

IL int Input(){
    RG int x = 0, z = 1; RG char c = getchar();
    for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
    for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
    return x * z;
}

int n, m, cnt, S, T, first[_], d[_], vis[_], l[_], r[_], p[_], len, pre[_];
struct Edge{
    int to, next, w;
} edge[_ << 1];
ll dis[2][_], f[2][_], F[_], ans;
struct Point{
    int u; ll d;

    IL int operator <(RG Point B) const{
        return d > B.d;
    }
};
queue <int> Que;
map <ll, int> M;
priority_queue <Point> Q;
vector <int> al[_], ar[_];

IL void Add_Graph(RG int u, RG int v, RG int w){
    edge[cnt] = (Edge){v, first[u], w}, first[u] = cnt++;
}

IL void Dijkstra(RG int op){
    for(RG int i = 1; i <= n; ++i) dis[op][i] = (ll)1e18, vis[i] = 0;
    if(!op) f[op][S] = 1, dis[op][S] = 0, Q.push((Point){S, 0});
    else f[op][T] = 1, dis[op][T] = 0, Q.push((Point){T, 0});
    while(!Q.empty()){
        RG Point x = Q.top(); Q.pop();
        if(vis[x.u]) continue;
        vis[x.u] = 1;
        for(RG int e = first[x.u]; e != -1; e = edge[e].next){
            RG int v = edge[e].to, w = edge[e].w;
            if(x.d + w < dis[op][v]){
                dis[op][v] = x.d + w, f[op][v] = f[op][x.u];
                Q.push((Point){v, x.d + w});
                if(op) pre[v] = x.u;
            }
            else if(x.d + w == dis[op][v]) f[op][v] += f[op][x.u];
        }
    }
}

IL int Check(RG int x, RG ll w, RG int y, RG int op){
    return dis[op][x] + w + dis[!op][y] == dis[0][T];
}

IL void TopSort(RG int op){
    for(RG int i = 1; i <= n; ++i)
        for(RG int e = first[i]; e != -1; e = edge[e].next){
            RG int v = edge[e].to, w = edge[e].w;
            if(Check(i, w, v, op)) ++d[v];
        }
    for(RG int i = 1; i <= n; ++i) if(!d[i]) Que.push(i);
    while(!Que.empty()){
        RG int u = Que.front(); Que.pop();
        for(RG int e = first[u]; e != -1; e = edge[e].next){
            RG int v = edge[e].to, w = edge[e].w;
            if(!Check(u, w, v, op)) continue;
            op ? r[v] = min(r[v], r[u]) : l[v] = max(l[v], l[u]);
            if(!--d[v]) Que.push(v);
        }
    }
}

int main(RG int argc, RG char* argv[]){
    Fill(first, -1), n = Input(), m = Input(), S = Input(), T = Input();
    for(RG int i = 1; i <= m; ++i){
        RG int u = Input(), v = Input(), w = Input();
        Add_Graph(u, v, w), Add_Graph(v, u, w);
    }
    Dijkstra(0);
    if(!f[0][T]) return printf("%lld\n", 1LL * n * (n - 1) >> 1), 0;
    Dijkstra(1);
    for(RG int i = S; i; i = pre[i]) p[++len] = i, l[i] = len + 1, r[i] = len - 1;
    for(RG int i = 1; i <= n; ++i) if(!(l[i] + r[i])) l[i] = 1, r[i] = len;
    TopSort(0), TopSort(1);
    for(RG int i = 1; i <= n; ++i){
        if(dis[0][i] + dis[1][i] == dis[0][T]) F[i] = f[0][i] * f[1][i];
        if(l[i] > r[i]) continue;
        al[l[i]].push_back(i), ar[r[i]].push_back(i);
    }
    for(RG int i = 1; i <= len; ++i){
        for(RG int l = al[i].size(), j = 0; j < l; ++j) ++M[F[al[i][j]]];
        ans += M[F[T] - F[p[i]]];
        for(RG int l = ar[i].size(), j = 0; j < l; ++j) --M[F[ar[i][j]]];
    }
    return printf("%lld\n", ans), 0;
}

Bzoj5109: [CodePlus 2017]大吉大利,晚上吃雞!