title

BZOJ 5109

LUOGU 4061

题意:

一张 \(n\) 个点 \(m\) 条无向边的图,节点编号为 \(1\) 到 \(n\) ,每条边具有一个正整数的长度。

假定大魔王都会从 \(S\) 点出发到达 \(T\) 点( \(S\) 和 \(T\) 已知),并且只会走最短路,皮皮和毛毛会在 \(A\) 点和 \(B\) 点埋伏大魔王。

为了保证一定能埋伏到大魔王,同时又想留大魔王一条生路,皮皮和毛毛约定 \(A\) 点和 \(B\) 点必须满足:

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

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

analysis

这道题有个梗,网友 \(blog\) 说:

所有图都是随机的,所有数据中从 \(S\) 到 \(T\) 的最短路最多只有 1 条,

所以呢,本题其实只需要先特判 \(S\) 和 \(T\) 是否连通,若不连通则输出 \(C^2_n\) ,否则随便找一条 \(S\) 到 \(T\) 的最短路,设路径上的点数为 \(len\) ,输出 \(len*(n-len)\) 即能得到满分。

然而我也没有去试,所以对真伪不知情,只是当个笑话放在这里(现在看来是真的)。

正解的思路真的是很好的。

因为大魔王(话说他是谁?)一定走最短路,所以处理出以 \(S\) 为源点的最短路和以 \(T\) 为源点的最短路,这是很显然的(毕竟我看题后,马上就赶紧敲了这个函数,因为怕后面啥都想不到了)。

这里迎来第一个分界点(其实也比较显然了):

  • 从 \(S\) 到 \(T\) 根本就不联通,这时候答案为 \(C^2_n\) (其实就是上面的话重说一遍,逃。
  • 否则(开始正解的道路,不要再看上面的骗分了),
    • 随便找出一条最短路(怎么还一样?),那么最终的 \(A\) 或者 \(B\) 一定有一个点在这条最短路上面(可不一样了吧),我们设在路径上的是 \(A\) 。
    • 于是我们枚举所有点 \(B\) ,考虑它可以搭配哪些合法的点 \(A\) 。
    • 为了满足条件 \(2\) ,可以选择的点 \(A\) 一定在一段区间中(如果能从 \(B\) 走到 \(A\) ,那么 \(B\) 也一定能走到 \(A\) 后面的点;如果 \(A\) 能走到 \(B\) ,那么 \(A\) 前面的点也一定能走到 \(B\) ),我们可以先求出最短路径图,然后在正图和反图上分别跑拓扑排序 \(+DP\) ,就能得出每个 \(B\) 的合法 \(A\) 区间。
    • 这时候再去考虑去满足条件 \(1\) ,可以用拓扑排序求出经过点 \(i\) 的最短路径条数 \(f[i]\) ,那么如果 \(A\) 和 \(B\) 满足条件 \(1\) ,等价于 \(f[A]+f[B]=f[T]\) ,所以可以采用差分的方式,将每个 \(B\) 的 \(f[i]\) 都扔到 \(A\) 区间,枚举所有的 \(A\) ,然后用 \(map\) 当前有多少个点的 \(f[i]\) 等于一个数,每枚举到一个 \(A\) ,就查询一下有多少个点的 \(f[i]\) 等于 \(f[T]-f[A]\) 即可。

这题被 CQzhangyu 测出来所有的图都是随机的,才有了那个梗(当然,这个梗最初也是人家提出来的),真的很厉害!

code

#include<bits/stdc++.h>#define mp std::make_pair
typedef long long ll;
typedef std::pair<ll,int> pli;
const int maxn=1e5+10;
typedef int iarr[maxn];
typedef ll larr[maxn];
const ll inf=0x3f3f3f3f3f3f3f3fll;namespace IO
{char buf[1<<15],*fs,*ft;inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }template<typename T>inline void read(T &x){x=0;T f=1, ch=getchar();while (!isdigit(ch) && ch^'-') ch=getchar();if (ch=='-') f=-1, ch=getchar();while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();x*=f;}char Out[1<<24],*fe=Out;inline void flush() { fwrite(Out,1,fe-Out,stdout); fe=Out; }template<typename T>inline void write(T x,char str){if (!x) *fe++=48;if (x<0) *fe++='-', x=-x;T num=0, ch[20];while (x) ch[++num]=x%10+48, x/=10;while (num) *fe++=ch[num--];*fe++=str;}
}using IO::read;
using IO::write;template<typename T>inline bool chkMin(T &a,const T &b) { return a>b ? (a=b, true) : false; }
template<typename T>inline bool chkMax(T &a,const T &b) { return a<b ? (a=b, true) : false; }int ver[maxn<<1],Next[maxn<<1],head[maxn],len=1;
ll edge[maxn<<1];
inline void add(int x,int y,ll z)
{ver[++len]=y,edge[len]=z,Next[len]=head[x],head[x]=len;
}int n,m,s,t,pre[maxn];//s~t 最短路上的点的前驱
larr dist,d;//dist s为源点的最短路,d t为源点的最短路
bool vis[maxn];
inline void Dijkstra()//分别跑出以 s、t 为源点的最短路
{memset(dist,0x3f,sizeof(dist));memset(vis,0,sizeof(vis));std::priority_queue<pli,std::vector<pli>,std::greater<pli> >q;q.push(mp(0,s)), dist[s]=0;while (!q.empty()){int x=q.top().second;q.pop();if (vis[x]) continue;vis[x]=1;for (int i=head[x]; i; i=Next[i]){int y=ver[i], z=edge[i];if (chkMin(dist[y],dist[x]+z)) q.push(mp(dist[y],y));}}memset(d,0x3f,sizeof(d));memset(vis,0,sizeof(vis));q.push(mp(0,t)), d[t]=0;while (!q.empty()){int x=q.top().second;q.pop();if (vis[x]) continue;vis[x]=1;for (int i=head[x]; i; i=Next[i]){int y=ver[i], z=edge[i];if (chkMin(d[y],d[x]+z)) pre[y]=x, q.push(mp(d[y],y));}}
}iarr deg,lm,rm;
larr f,f1,f2;
inline void Topsort()//拓扑排序
{std::queue<int>q;f1[s]=1, f2[t]=1;//for (int i=1; i<=n; ++i)if (!deg[i]) q.push(i);while (!q.empty()){int x=q.front();q.pop();for (int i=head[x]; i; i=Next[i]) if (edge[i]==-1){int y=ver[i];f1[y]+=f1[x], chkMax(lm[y],lm[x]);if (!--deg[y]) q.push(y);}}for (int x=1; x<=n; ++x)for (int i=head[x]; i; i=Next[i]) if (edge[i]==-2){int y=ver[i];++deg[y];}for (int i=1; i<=n; ++i)if (!deg[i]) q.push(i);while (!q.empty()){int x=q.front();q.pop();for (int i=head[x]; i; i=Next[i]) if (edge[i]==-2){int y=ver[i];f2[y]+=f2[x], chkMin(rm[y],rm[x]);if (!--deg[y]) q.push(y);}}
}std::vector<int> lp[maxn], rp[maxn];
std::vector<int>::iterator it;
std::map<ll,int>M;
int path[maxn],cnt;ll ans;
int main()
{read(n);read(m);read(s);read(t);for (int i=1; i<=m; ++i){int x,y; ll z;read(x), read(y), read(z);add(x,y,z), add(y,x,z);}Dijkstra();if (dist[t]>=inf) ans=1ll*n*(n-1)/2ll, write(ans,'\n');else{for (int i=s; i; i=pre[i]) path[++cnt]=i, lm[i]=cnt+1, rm[i]=cnt-1;for (int i=1; i<=n; ++i) if (!lm[i]) lm[i]=1, rm[i]=cnt;for (int x=1; x<=n; ++x)for (int i=head[x]; i; i=Next[i]){int y=ver[i];if (edge[i]>0 && dist[t]==dist[x]+d[y]+edge[i]) edge[i]=-1, edge[i^1]=-2, ++deg[y];}Topsort();for (int i=1; i<=n; ++i){f[i]=f1[i]*f2[i];if (lm[i]<=rm[i]) lp[lm[i]].push_back(f[i]), rp[rm[i]].push_back(f[i]);}for (int i=1; i<=cnt; ++i){for (it=lp[i].begin(); it!=lp[i].end(); ++it) ++M[*it];ans+=1ll*M[f[t]-f[path[i]]];for (it=rp[i].begin(); it!=rp[i].end(); ++it) --M[*it];}write(ans,'\n');}IO::flush();return 0;
}

转载于:https://www.cnblogs.com/G-hsm/p/BZOJ_5109.html

BZOJ 5109: [CodePlus 2017]大吉大利,晚上吃鸡! 最短路 拓扑 Dp相关推荐

  1. HTML5+css+JS实现页面打枪声音特效减压玩法 PUBG 大吉大利 今晚吃鸡

    HTML5+css+JS实现页面打枪声音特效减压玩法 PUBG 大吉大利 今晚吃鸡 css部分 *{margin: 0;padding:0;}body{min-height:100vh;overflo ...

  2. 老司机带你在MySQL领域“大吉大利,晚上吃鸡”

    关注↑↑↑我们获得更多精彩内容! 作者 | 张甦, 数据库领域的专家和知名人士.图书<MySQL王者晋级之路>作者,51CTO 专家博主.近10年互联网线上处理及培训经验,专注于 MySQ ...

  3. 大吉大利-今晚吃鸡-枪械

    题目描述 在绝地求生(吃鸡)游戏里,不同的枪支有不同的威力,更是可以搭配不同的配件,以提升枪支的性能. 每一把枪都有其威力及其可装备配件种类.每一个配件有其所属种类,可以为枪支提供威力的百分比加成.每 ...

  4. 大吉大利-今晚吃鸡-跑毒

    题目描述 现在有一款很火的游戏playerunknown's battlegrounds,人称"吃鸡",在里面经常面临跑毒(从安全区外跑进安全区内)的问题,在安全区外,人们会处于中 ...

  5. 大吉大利 今晚吃鸡之跑毒篇

    现在有一款很火的游戏playerunknown's battlegrounds,人称"吃鸡",在里面经常面临跑毒(从安全区外跑进安全区内)的问题,在安全区外,人们会处于中毒状态,每 ...

  6. 大吉大利今晚吃鸡——枪械篇

    题目链接:点击打开链接 这题难点带就是输入?我是因为用float精度不够才不过的,改成double就ok了 #include <cstdio> using namespace std;in ...

  7. 大吉大利今晚吃鸡——跑毒篇

    题目链接:点击打开链接 问题 1. 边界部分恰好擦着的时候到底是死是活.......写到程序里就是有没有=的问题. 首先题目里明确指出打包的时候擦着就是死. 然后后面有个带着你理解第二个样例的部分,这 ...

  8. 计算机内存不足吃鸡怎么办,Win10玩吃鸡游戏提示虚拟内存不足怎么办?

    Win10玩吃鸡游戏提示"虚拟内存不足"怎么办? 最近吃鸡游戏非常火,大家都想大吉大利晚上吃鸡!因为吃鸡游戏对电脑配置的要求非常高,所以很多用户在玩吃鸡手游时会遇到各种问题,最常见 ...

  9. 吃鸡一直显示服务器,吃鸡一直显示服务器未连接 | 手游网游页游攻略大全

    发布时间:2017-05-12 怎么吃鸡?相信很多新手玩家在经过几十甚至上百小时的游戏洗礼之后,心中对于吃鸡的疑惑也是越来越大,为什么有时候明明开局不顺却最后吃鸡,而有时候明明很肥却送了快递.所以今天 ...

  10. 为什么吃鸡显示连接不到服务器,为什么吃鸡进游戏显示连接不上 | 手游网游页游攻略大全...

    发布时间:2015-09-28 原因:显卡太老,不支持DX9.0c+SM3.0 解决方法:换新显卡 标签: 发布时间:2017-05-12 怎么吃鸡?相信很多新手玩家在经过几十甚至上百小时的游戏洗礼之 ...

最新文章

  1. [CODEVS] 2189 数字三角形W
  2. Google Maps API v2 android版本开发 国内手机不支持google play Service相关问题解决--图文教程
  3. 泛型--定制泛型接口、泛型类--介绍篇
  4. {php mysql}
  5. koa2-cookie-session
  6. mysql 数据迁移_【AWS 功能】Mysql 数据库迁移至Amazon RDS方案
  7. 2999元!联想Z6 Pro开启预售:搭载骁龙855+后置高清四摄
  8. SQL Server实际执行计划COST欺骗案例
  9. 数据迁移其实是很难的
  10. .net 考试系统人一多就断开了_【项目】Java在线考试系统
  11. 【程序设计入门-C语言】翁凯——初学者视角1
  12. python学期总结
  13. 机器学习项目中不可忽视的一个密辛 - 大数定理、中心极限定理
  14. Android 指纹验证
  15. datasource java用法_Java Datasource介绍
  16. 【Python笔记】pyspark.sql库
  17. Java ClassLoader类加载机制(二)类加载器
  18. 怎样快速提升自身的编程水平?
  19. 如何“谨慎”使用“数据驱动”的风控模型(三)——监控篇
  20. 慎用chrome密码记住功能

热门文章

  1. Jedis Connection Pool
  2. 什么是V2X?如何通过V2X技术实现5G智慧交通?
  3. MATLAB批量读取文件夹名,文件名,文件数据
  4. 人工解决问题和用计算机解决问题的相同点,第2学时:计算机解决问题的过程_20120207110033703.doc...
  5. 红米note2卡在android,红米note2怎么插卡?红米note2插卡流程详解
  6. 100部5星国外经典电影
  7. [Python从零到壹] 一.为什么我们要学Python及基础语法详解
  8. policy服务器未能登录,win7电脑提示group policy client服务未能登录的解决方法
  9. 微信账号和系统账号绑定
  10. 从基础接口工具postman开始夯实软件测试基础(一)