zoukankan      html  css  js  c++  java
  • Bzoj5109: [CodePlus 2017]大吉大利,晚上吃鸡!

    题面

    传送门

    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
    ", 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
    ", 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
    ", 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
    ", ans), 0;
    }
    
    
  • 相关阅读:
    监控平台
    自动化配置管理
    软件课程设计(15)
    软件课程设计(14)
    软件课程设计(13)
    软件课程设计(12)
    软件课程设计(11)
    软件课程设计(10)
    软件课程设计(9)
    参考资料
  • 原文地址:https://www.cnblogs.com/cjoieryl/p/8691806.html
Copyright © 2011-2022 走看看