Bzoj5109: [CodePlus 2017]大吉大利,晚上吃鸡!
2018-04-02 11:34
393 查看
题面
传送门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]大吉大利,晚上吃鸡!
- BZOJ5109:[CodePlus 2017]大吉大利,晚上吃鸡! (最短路+Hash表+二进制压位)
- [传递闭包 BITSET] 「CodePlus 2017 11 月赛」大吉大利,晚上吃鸡!
- [最短路][DP][传递闭包] BZOJ 5109 && LOJ #6252. 「CodePlus 2017 11 月赛」大吉大利,晚上吃鸡!
- 「CodePlus 2017 11 月赛」大吉大利,晚上吃鸡!
- bzoj5109: [CodePlus 2017]大吉大利,晚上吃鸡!
- 【BZOJ5109】[CodePlus 2017]大吉大利,晚上吃鸡! 最短路+拓扑排序+DP
- 「CodePlus 2017 11 月赛」大吉大利,晚上吃鸡!(dij+bitset)
- BZOJ5109 CodePlus 2017大吉大利,晚上吃鸡!(最短路+拓扑排序+bitset)
- [BZOJ5109][LOJ #6252][P4061][CodePlus 2017 11月赛]大吉大利,今晚吃鸡!(最短路+拓扑排序+传递闭包+map+bitset(hash+压位))
- 老司机带你在MySQL领域“大吉大利,晚上吃鸡”
- [BZOJ5109]大吉大利,晚上吃鸡!
- 张书乐:“大吉大利、晚上吃鸡”背后有隐藏剧情
- GMA Round 1 大吉大利,晚上吃鸡
- [贪心]「CodePlus 2017 11 月赛」可做题
- CodePlus 2017 12 月赛 白金元首与独舞 矩阵树定理求有向图生成树数量
- 大吉大利,今晚吃鸡——跑毒篇
- 洛谷 P4032 「CodePlus 2017 12 月赛」火锅盛宴(splay+堆)
- nowcoder 67 F 大吉大利,今晚吃鸡——跑毒篇
- LOJ6253:「CodePlus 2017 11 月赛」Yazid 的新生舞会 (线段树)