7.12 NOI模拟赛 探险队 期望 博弈 dp 最坏情况下最优策略 可并堆
LINK:探险队


非常难的题目 考试的时候爆零了 完全没有想到到到底怎么做 (当时去刚一道数论题了。
首先考虑清楚一件事情 就是当前是知道整张地图的样子 但是不清楚到底哪条边断了。
所以我们要做的其实就是选择最优的路线 使得遇到断边情况下是最优的。
可以发现在某个点出现断边的时候 此时断的一定是这个点到终点最短路上的边 这样是最差的结果。
那么其实就是断边只会断由T发出的最短路树上的边。
到达某个点知道断边之后 其实要求出断开这条边再到T的最短路。
暴力是\(nm\cdot logn\)的 考虑更快的求法 当前点可以通过非最短路边到达另外一个点 或者是自己子树内的一条边到达另外的点再沿着另外的点的最短路走。
维护子树内这样边的最小值可以线段树 最快的做法是 可并堆。记\(h_x\)表示x处断了最短路的边到T的最小值。
复杂度\(n\cdot logn\).
接下来考虑怎么求答案.
一个比较\(naiv\)e的想法是 不是求最优线路么?可以把所有最优的线路给搜出来。
对于初始选择这条线路的最大代价为\(\max{h_x+dis_x}\)所有之中选\(min\)即可。
这启示我们求S到T的所有路径的代价为上述的那个东西 从S开始dp没有什么用 因为当前的选择 需要知道以后的决策。
如 当前如果选择断边 是要知道以后断边的结果会更好 当前选择不断边 要知道以后断边的结果会更差.
所以需要倒序dp.
设\(f_x\)表示从x到T的最短路/设\(f_{x,0/1}\)表示从x到T的最短路此时是否断边了.
那么其实我们知道以后的状态就可以决断现在的状态了.
\(f_{x,0}=f_{tn,0}+e[i],f_{x,1}=max(min(f_{tn,1}+e[i]),h_x)\)
最后的答案即为\(f_{S,1}\) 由此可以发现好像第一个状态不是很必要。
为了让状态具有最优性可以利用dij进行转移。
感觉很难 希望以后遇到这种问题可以会做吧!
code
//#include<bits\stdc++.h>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<cctype>
#include<cstdlib>
#include<queue>
#include<deque>
#include<stack>
#include<vector>
#include<algorithm>
#include<utility>
#include<bitset>
#include<set>
#include<map>
#define ll long long
#define db double
#define INF 1000000000000000000ll
#define ldb long double
#define pb push_back
#define put_(x) printf("%d ",x);
#define get(x) x=read()
#define gt(x) scanf("%d",&x)
#define gi(x) scanf("%lf",&x)
#define put(x) printf("%d\n",x)
#define putl(x) printf("%lld\n",x)
#define gc(a) scanf("%s",a+1)
#define rep(p,n,i) for(RE int i=p;i<=n;++i)
#define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
#define fep(n,p,i) for(RE int i=n;i>=p;--i)
#define vep(p,n,i) for(RE int i=p;i<n;++i)
#define pii pair<ll,int>
#define mk make_pair
#define RE register
#define P 1000000007
#define gf(x) scanf("%lf",&x)
#define pf(x) ((x)*(x))
#define uint unsigned long long
#define ui unsigned
#define EPS 1e-4
#define sq sqrt
#define S second
#define F first
#define V vector
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
RE int x=0,f=1;RE char ch=getc();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
return x*f;
}
const int MAXN=200010,maxn=500010<<1;
int n,m,ss,tt,cnt,len=1;
ll dis[MAXN],h[MAXN],c[MAXN];
int vis[MAXN],v[MAXN],f[MAXN][20],Log[MAXN],d[MAXN];V<int>g[MAXN],s[MAXN];
int lin[MAXN],pos[maxn],nex[maxn],ver[maxn],e[maxn];
int root[MAXN],lc[maxn],rc[maxn],b[maxn];
pii w[maxn];
inline void add(int x,int y,int z)
{
ver[++len]=y;
nex[len]=lin[x];
lin[x]=len;
e[len]=z;
}
priority_queue<pii> q;
inline void dij()
{
q.push(mk(0,tt));
rep(1,n,i)dis[i]=INF;dis[tt]=0;
while(q.size())
{
int x=q.top().S;q.pop();
if(vis[x])continue;
vis[x]=1;
go(x)
{
if(dis[tn]>dis[x]+e[i])
{
dis[tn]=dis[x]+e[i];
f[tn][0]=x;v[tn]=i;
q.push(mk(-dis[tn],tn));
}
}
}
}
inline void dfs(int x)
{
d[x]=d[f[x][0]]+1;
rep(1,Log[d[x]],i)f[x][i]=f[f[x][i-1]][i-1];
vep(0,g[x].size(),j)dfs(g[x][j]);
}
inline int LCA(int x,int y)
{
if(d[x]<d[y])swap(x,y);
fep(Log[d[x]],0,i)if(d[f[x][i]]>=d[y])x=f[x][i];
if(x==y)return x;
fep(Log[d[x]],0,i)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
return f[x][0];
}
inline int merge(int x,int y)//左偏树的性质 左边比右边满.
{
if(!x||!y)return x|y;
if(w[x]>w[y])swap(x,y);
rc[x]=merge(rc[x],y);
if(b[lc[x]]<b[rc[x]])swap(lc[x],rc[x]);
b[x]=b[rc[x]]+1;
return x;
}
inline void dp(int x)
{
vep(0,g[x].size(),i)dp(g[x][i]),root[x]=merge(root[x],root[g[x][i]]);
vep(0,s[x].size(),i)root[x]=merge(root[x],s[x][i]);
while(root[x])
{
if(d[w[root[x]].S]>=d[x])
{
root[x]=merge(lc[root[x]],rc[root[x]]);
continue;
}
else
{
h[x]=w[root[x]].F-dis[x];
break;
}
}
}
int main()
{
//freopen("1.in","r",stdin);
freopen("expedition.in","r",stdin);
freopen("expedition.out","w",stdout);
get(n);get(m);get(ss);get(tt);
if(ss==tt){puts("0");return 0;}
rep(1,m,i)
{
int get(x),get(y),get(z);
add(x,y,z);add(y,x,z);
}
dij();Log[0]=-1;
rep(1,n,i)
{
if(f[i][0])g[f[i][0]].pb(i);
Log[i]=Log[i>>1]+1;
pos[v[i]>>1]=1;h[i]=INF;c[i]=INF;vis[i]=0;
}
dfs(tt);
rep(1,m,i)
{
if(pos[i])continue;
w[++cnt]=mk(dis[ver[i<<1]]+dis[ver[i<<1|1]]+e[i<<1],LCA(ver[i<<1],ver[i<<1|1]));
s[ver[i<<1]].pb(cnt);++cnt;w[cnt]=w[cnt-1];s[ver[i<<1|1]].pb(cnt);
}
dp(tt);
q.push(mk(0,tt));c[tt]=0;h[tt]=0;
while(q.size())
{
int x=q.top().S;q.pop();
if(vis[x])continue;
vis[x]=1;
go(x)
{
if(c[tn]>max(c[x],h[x])+e[i])
{
c[tn]=max(c[x],h[x])+e[i];
q.push(mk(-max(c[tn],h[tn]),tn));
}
}
}
if(max(h[ss],c[ss])>=INF)puts("-1");
else putl(max(h[ss],c[ss]));
return 0;
}
7.12 NOI模拟赛 探险队 期望 博弈 dp 最坏情况下最优策略 可并堆的更多相关文章
- 7.12 NOI模拟赛 生成树 装压dp vector装压
LINK:生成树 这场比赛我打的真失败 T3是比较容易的 却一直刚 那道"数论" 10分其实搜一下全排列. 30分容易想到对边进行装压dp. 不过存在一些细节 可以对于一个连通块的 ...
- 7.12 NOI模拟赛 积性函数求和 数论基础变换 莫比乌斯反演
神题! 一眼powerful number 复习了一下+推半天. 可以发现G函数只能为\(\sum_{d}[d|x]d\) 不断的推 可以发现最后需要求很多块G函数的前缀和 发现只有\(\sqrt(n ...
- 7.9 NOI模拟赛 C.走路 背包 dp 特异性
(啊啊啊 什么考试的时候突然降智这题目硬生生没想出来. 容易发现是先走到某个地方 然后再走回来的 然后在倒着走的路径上选择一些点使得最后的得到的最多. 设\(f_{i,j}\)表示到达i这个点选择的价 ...
- NOI模拟赛 Day1
[考完试不想说话系列] 他们都会做呢QAQ 我毛线也不会呢QAQ 悲伤ING 考试问题: 1.感觉不是很清醒,有点困╯﹏╰ 2.为啥总不按照计划来!!! 3.脑洞在哪里 4.把模拟赛当作真正的比赛,紧 ...
- 6.28 NOI模拟赛 好题 状压dp 随机化
算是一道比较新颖的题目 尽管好像是两年前的省选模拟赛题目.. 对于20%的分数 可以进行爆搜,对于另外20%的数据 因为k很小所以考虑上状压dp. 观察最后答案是一个连通块 从而可以发现这个连通块必然 ...
- 【2019.3.20】NOI模拟赛
题目 这里必须标记一下那个傻逼问题,再不解决我人就没了! 先放一个 $T3$ $20$ 分暴力 #include<bits/stdc++.h> #define rep(i,x,y) for ...
- 7.1 NOI模拟赛 凸包套凸包 floyd 计算几何
计算几何之所以难学 就是因为太抽象了 不够直观 而且情况很多 很繁琐 甚至有一些东西不清不楚.. 这道题注意到题目中的描述 一个鸽子在两个点所连直线上也算. 通过看题解 发现这个地方并非直线而是线段 ...
- 10年省赛-Greatest Number (二分+暴力) + 12年省赛-Pick apples(DP) + UVA 12325(暴力-2次枚举)
题意:给你n个数,在里面取4个数,可以重复取数,使和不超过M,求能得到的最大的数是多少: 思路:比赛时,和之前的一个题目很像,一直以为是体积为4(最多选择四次)的完全背包,结果并不是,两两求和,然后二 ...
- 【2018.12.10】NOI模拟赛3
题目 WZJ题解 大概就是全场就我写不过 $FFT$ 系列吧……自闭 T1 奶一口,下次再写不出这种 $NTT$ 裸题题目我就艹了自己 -_-||| 而且这跟我口胡的自创模拟题 $set1$ 的 $T ...
随机推荐
- redo log 与 binlog
redo log 与 binlog redo log redo log (重做日志)是处于存储引擎层的,是InnoDB引擎特有的 redo log 存储的是物理日志 --- 即,"在某个 ...
- Buy A Ticket(图论)
Buy A Ticket 题目大意 每个点有一个点权,每个边有一个边权,求对于每个点u的\(min(2*d(u,v)+val[v])\)(v可以等于u) solution 想到了之前的虚点,方便统计终 ...
- python—模块optparse的用法
1.什么是optparse: 在工作中我们经常要制定运行脚本的一些参数,因为有些东西是随着我么需求要改变的,所以在为们写程序的时候就一定不能把写死,这样我们就要设置参数 optparse用于处理命令行 ...
- Xshell6 优化
Xshell6 优化
- MySQL 快速删除大量数据(千万级别)的几种实践方案
笔者最近工作中遇见一个性能瓶颈问题,MySQL表,每天大概新增776万条记录,存储周期为7天,超过7天的数据需要在新增记录前老化.连续运行9天以后,删除一天的数据大概需要3个半小时(环境:128G, ...
- hihoCoder 1114 小Hi小Ho的惊天大作战:扫雷·一 最详细的解题报告
题目来源:小Hi小Ho的惊天大作战:扫雷·一 解题思路:因为只要确定了第一个是否有地雷就可以推算出后面是否有地雷(要么为0,要么为1,如果不是这两个值就说明这个方案行不通),如果两种可能中有一种成功, ...
- TCP 进阶
转自: https://www.cnblogs.com/caoyusongnet/p/9087633.html 一. 端口号 标准的端口号由 Internet 号码分配机构(IANA)分配.这组数字被 ...
- 随笔java面试基础
转:http://blog.csdn.net/wenwen360360/article/details/54969418 Application ―Java应用程序”是可以独立运行的Java程序.由J ...
- Cyber Security - Palo Alto Firewall Interface Types
Multiple options to integrate the Palo Alto Firewall into your: Network Layer 2 interfaces and VLAN ...
- OSCP Learning Notes - Post Exploitation(4)
Pivoting 1. Edit the virtual network settings of the Vmware. 2. Set the Network Adapter(s) of Kali L ...