[BZOJ5109]大吉大利,晚上吃鸡!

题目大意:

一张\(n(n\le5\times10^4)\)个点\(m(m\le5\times10^4)\)条边的无向图,节点编号为\(1\)到\(n\),边权为正整数。给定\(S\)和\(T\),显然从\(S\)到\(T\)的最短路有一种或多种方案。

选择\(A,B\)两个点,约定\(A\)点和\(B\)点必须满足:

  1. 所有可能路径中,必定会经过\(A\)点和\(B\)点中的任意一点;
  2. 所有可能路径中,不存在一条路径同时经过\(A\)点和\(B\)点。

求满足上面两个条件的\(A,B\)点对有多少个,交换\(A,B\)的顺序算相同的方案。

思路:

首先用Dijkstra求出最短路网络,显然这是一个DAG。

在DAG上DP求出一个点到\(S/T\)的方案数,将它们相乘即为经过这个点的路径数,记作\(F(i)\)。我们同样也可以用bitset求出经过这个点的路径上可能经过的点,记作\(S(i)\)。

而题目所求的\(A\)和\(B\)相当于需要满足以下两个条件:

  1. \(F(A)+F(B)=F(T)\);
  2. \(A\notin F(B)\)且\(B\notin F(A)\)。

显然枚举\(A\)和\(B\)会超时,由于\(F(A)+F(B)=F(T)\)。我们可以开一个map<int,bitset>保存\(F(B)=F(T)-F(A)\)的可能的\(B\)。

此时我们只需要枚举\(A\),然后在map上查找对应的\(B\)即可。

源代码:

  1. #include<cstdio>
  2. #include<cctype>
  3. #include<vector>
  4. #include<bitset>
  5. #include<climits>
  6. #include<functional>
  7. #include<tr1/unordered_map>
  8. #include<ext/pb_ds/priority_queue.hpp>
  9. inline int getint() {
  10. register char ch;
  11. while(!isdigit(ch=getchar()));
  12. register int x=ch^'0';
  13. while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
  14. return x;
  15. }
  16. typedef long long int64;
  17. const int N=5e4+1,M=5e4;
  18. struct Edge2 {
  19. int u,v,w;
  20. };
  21. Edge2 edge[M];
  22. struct Edge3 {
  23. int to,w;
  24. };
  25. std::vector<Edge3> e3[N];
  26. inline void add_edge(const int &u,const int &v,const int &w) {
  27. e3[u].push_back((Edge3){v,w});
  28. e3[v].push_back((Edge3){u,w});
  29. }
  30. bool vis[N];
  31. int n,m,s,t,ind[N],ind2[N],outd[N];
  32. int64 diss[N],dist[N],f[N],g[N],ans;
  33. struct Vertex {
  34. int id;
  35. int64 d;
  36. bool operator > (const Vertex &rhs) const {
  37. return d>rhs.d;
  38. }
  39. };
  40. inline void dijkstra(const int &s,int64 dis[]) {
  41. static __gnu_pbds::priority_queue<Vertex,std::greater<Vertex> > q;
  42. static __gnu_pbds::priority_queue<Vertex,std::greater<Vertex> >::point_iterator p[N];
  43. for(register int i=1;i<=n;i++) {
  44. p[i]=q.push((Vertex){i,dis[i]=i==s?0:LLONG_MAX});
  45. }
  46. while(!q.empty()&&q.top().d!=LLONG_MAX) {
  47. const int x=q.top().id;
  48. q.pop();
  49. for(register unsigned i=0;i<e3[x].size();i++) {
  50. const int &y=e3[x][i].to,&w=e3[x][i].w;
  51. if(dis[x]+w<dis[y]) {
  52. q.modify(p[y],(Vertex){y,dis[y]=dis[x]+w});
  53. }
  54. }
  55. }
  56. q.clear();
  57. }
  58. std::vector<int> e[N],e4[N];
  59. inline void add_edge(const int &u,const int &v) {
  60. e[u].push_back(v);
  61. e4[v].push_back(u);
  62. ind[v]++;
  63. ind2[v]++;
  64. outd[u]++;
  65. }
  66. std::queue<int> q;
  67. std::bitset<N> b[N];
  68. inline void kahn2() {
  69. q.push(t);
  70. g[t]=1;
  71. while(!q.empty()) {
  72. const int &x=q.front();
  73. for(register unsigned i=0;i<e4[x].size();i++) {
  74. const int &y=e4[x][i];
  75. g[y]+=g[x];
  76. if(!--outd[y]) q.push(y);
  77. }
  78. q.pop();
  79. }
  80. }
  81. inline void kahn() {
  82. q.push(s);
  83. f[s]=1;
  84. while(!q.empty()) {
  85. const int &x=q.front();
  86. b[x][x]=true;
  87. for(register unsigned i=0;i<e[x].size();i++) {
  88. const int &y=e[x][i];
  89. b[y]|=b[x];
  90. f[y]+=f[x];
  91. if(!--ind[y]) q.push(y);
  92. }
  93. q.pop();
  94. }
  95. }
  96. inline void kahn3() {
  97. q.push(s);
  98. while(!q.empty()) {
  99. const int &x=q.front();
  100. b[0][x]=true;
  101. b[x]=b[0]^b[x];
  102. for(register unsigned i=0;i<e[x].size();i++) {
  103. const int &y=e[x][i];
  104. if(!--ind2[y]) q.push(y);
  105. }
  106. q.pop();
  107. }
  108. }
  109. std::tr1::unordered_map<int64,std::bitset<N> > map;
  110. int main() {
  111. n=getint(),m=getint(),s=getint(),t=getint();
  112. for(register int i=0;i<m;i++) {
  113. const int u=getint(),v=getint(),w=getint();
  114. edge[i]=(Edge2){u,v,w};
  115. add_edge(u,v,w);
  116. }
  117. dijkstra(s,diss);
  118. if(diss[t]==LLONG_MAX) {
  119. printf("%lld\n",(int64)n*(n-1)/2);
  120. return 0;
  121. }
  122. dijkstra(t,dist);
  123. for(register int i=1;i<=n;i++) e3[i].clear();
  124. for(register int i=0;i<m;i++) {
  125. int u=edge[i].u,v=edge[i].v,w=edge[i].w;
  126. if(diss[u]>diss[v]) std::swap(u,v);
  127. if(diss[u]+w+dist[v]==diss[t]) {
  128. add_edge(u,v);
  129. vis[u]=vis[v]=true;
  130. }
  131. }
  132. int cnt=0;
  133. for(register int i=1;i<=n;i++) cnt+=!vis[i];
  134. kahn2();
  135. kahn();
  136. kahn3();
  137. for(register int i=1;i<=n;i++) {
  138. if(vis[i]) map[f[i]*g[i]][i]=true;
  139. }
  140. for(register int i=1;i<=n;i++) {
  141. if(!vis[i]) continue;
  142. if(map.count(f[t]-f[i]*g[i])) ans+=(map[f[t]-f[i]*g[i]]&b[i]).count();
  143. if(f[i]*g[i]==f[t]) ans+=cnt;
  144. }
  145. printf("%lld\n",ans);
  146. return 0;
  147. }

[BZOJ5109]大吉大利,晚上吃鸡!的更多相关文章

  1. 【BZOJ5109】[CodePlus 2017]大吉大利,晚上吃鸡! 最短路+拓扑排序+DP

    [BZOJ5109][CodePlus 2017]大吉大利,晚上吃鸡! Description 最近<绝地求生:大逃杀>风靡全球,皮皮和毛毛也迷上了这款游戏,他们经常组队玩这款游戏.在游戏 ...

  2. GMA Round 1 大吉大利,晚上吃鸡

    传送门 大吉大利,晚上吃鸡 新年走亲访友能干点啥呢,咱开黑吃鸡吧. 这里有32个人,每个人都可能想玩或者不想玩,这样子一共有$2^{32}$种可能.而要开黑当然得4人4人组一队(四人模式),所以说如果 ...

  3. BZOJ5109 CodePlus 2017大吉大利,晚上吃鸡!(最短路+拓扑排序+bitset)

    首先跑正反两遍dij求由起点/终点到某点的最短路条数,这样条件一就转化为f(S,A)*f(T,A)+f(S,B)*f(T,B)=f(S,T).同时建出最短路DAG,这样图中任何一条S到T的路径都是最短 ...

  4. bzoj5109: [CodePlus 2017]大吉大利,晚上吃鸡!

    Description 最近<绝地求生:大逃杀>风靡全球,皮皮和毛毛也迷上了这款游戏,他们经常组队玩这款游戏.在游戏中,皮皮 和毛毛最喜欢做的事情就是堵桥,每每有一个好时机都能收到不少的快 ...

  5. [BZOJ5109/CodePlus2017]大吉大利,晚上吃鸡!

    Description 最近<绝地求生:大逃杀>风靡全球,皮皮和毛毛也迷上了这款游戏,他们经常组队玩这款游戏.在游戏中,皮皮和毛毛最喜欢做的事情就是堵桥,每每有一个好时机都能收到不少的快递 ...

  6. 「CodePlus 2017 11 月赛」大吉大利,晚上吃鸡!(dij+bitset)

    从S出发跑dij,从T出发跑dij,顺便最短路计数. 令$F(x)$为$S$到$T$最短路经过$x$的方案数,显然这个是可以用$S$到$x$的方案数乘$T$到$x$的方案数来得到. 然后第一个条件就变 ...

  7. 「CodePlus 2017 11 月赛」大吉大利,晚上吃鸡!

    n<=50000,m<=50000的图,给s和t,问有多少点对$(a,b)$满足 嗯. 不会. 首先最短路DAG造出来,然后两个条件转述一下:条件一,$N_a$表示从s到t经过a的路径,$ ...

  8. [Code+#1]大吉大利,晚上吃鸡!

    输入输出样例 输入样例#1: 7 7 1 7 1 2 2 2 4 2 4 6 2 6 7 2 1 3 2 3 5 4 5 7 2 输出样例#1: 6 输入样例#2: 5 5 1 4 1 2 1 1 3 ...

  9. luogu4061 大吉大利,晚上吃鸡!

    链接 最短路径\(dag\),一道好题. 题目大意:求一张图中满足下列要求的点对\((i,j)\)数量: 所有最短路径必定会经过 \(i\) 点和 \(j\) 点中的任意一点. 不存在一条最短路同时经 ...

随机推荐

  1. python端口扫描

    简易版: #author:Blood_Zero #coding:utf-8 import socket import sys PortList=[21,22,23,25,80,135] # host= ...

  2. zTree静态树与动态树的用法——(七)

    0.[简介] zTree 是利用 JQuery 的核心代码,实现一套能完成大部分常用功能的 Tree 插件 兼容 IE.FireFox.Chrome 等浏览器 在一个页面内可同时生成多个 Tree 实 ...

  3. 阿里面试回来,想和Java程序员谈一谈

    引言 其实本来真的没打算写这篇文章,主要是LZ得记忆力不是很好,不像一些记忆力强的人,面试完以后,几乎能把自己和面试官的对话都给记下来.LZ自己当初面试完以后,除了记住一些聊过的知识点以外,具体的内容 ...

  4. aarch64_o2

    opensips-event_rabbitmq-2.2.3-1.fc26.aarch64.rpm 2017-03-10 01:22 42K fedora Mirroring Project opens ...

  5. linux下/var/run目录下.pid文件的作用

    1.pid文件的内容用cat命令查看,可以看到内容只有一行,记录了该进程的ID 2.pid文件的作用防止启动多个进程副本 3.pid文件的原理进程运行后会给.pid文件加一个文件锁,只有获得该锁的进程 ...

  6. git —— 远程仓库(操作)

    运行目录:本地仓库目录 1.本地关联远程仓库 $ git remote add origin 你的远程库地址(SSH和HTTP都可以) 2.远程仓库为空,可选择合并远程仓库和本地仓库,远程库不为空时, ...

  7. java 闭包与回调

    闭包(closure)是一个可调用的对象,它记录了一些信息,这些信息来自于创建它的作用域. 内部类是面向对象的闭包,因为它不仅包含外围类对象(创建内部类的作用域)的信息,还自动拥有一个指向此外围类对象 ...

  8. Master和worker模式

    让和hadoop的设计思想是一样的,Master负责分配任务和获取任务的结果,worker是真正处理业务逻辑的. 使用ConcurrentLikedQueue去承载所有的任务,因为会有多个worker ...

  9. php取得当前时间函数

    php取得当前时间函数文章提供了php的几种获取当前时间的函数,date,time等哦,同时告诉我如何解决时区问题哦. php获取当前时间 使用函式 date() 实现 <?php echo $ ...

  10. Kylin使用笔记-1: 安装

    2016年1月14日 9:57:23 星期四 背景介绍     Apache Kylin是一个开源的分布式分析引擎,提供Hadoop之上的SQL查询接口及多维分析(OLAP)能力以支持超大规模数据,最 ...