Bubble Cup 8 finals G. Run for beer (575G)

题意:

给定一个带权无向图,每条边的代价为边权/当前速度,每次到达一个新节点,速度都会除以10。

求0号点到n-1号点的最小代价,如果多解输出点数最少的解,输出代价、路径点数、路径经过的点。

1<=边数<=10^5, 1<=点数<=10^5, 0<=边权<=9

题解:

比较有趣的一道题…难度不算太高,但一些地方比较容易想错…

这题的边代价可变本身并不是什么大问题,因为是图中所有边一起变大,

但是一开始就会遇到一个问题,就是总代价数字过大,没有办法直接存储和比较。

观察到边权的奇怪的条件,就会发现代价其实就是经过的边权拼起来的十进制数。

那么就有办法进行比较了。

对于任意两条到底终点的路径,如果没有前导零,一定是短的优于长的。

所以可以用BFS来处理。

首先为了排除前导零,从终点开始只走权值为0的边来BFS,求出每个可以无代价到达终点的点的路径。

然后从起点开始进行BFS。这个地方最容易错。

BFS时一般只知道和当前点直接相连的点和边的信息,所以可以先考虑理想情况,

即起点到当前点和目标点经过的路径中除了当前目标点以外的代价是相同的。

这时只需比较当前边的权是否小于目标点的代价中的最高位即可。

还有一种比较容易处理的情况是当前点的路径长度已经大于目标点路径,那么不更新。

然后还有一种情况就是当前点路径长度小于目标点,

因为是BFS,所以只有首次访问目标点时出现。(初始化为无穷大)

剩下的一种情况就是前面说的理想情况的一般化,不能保证之前的路径代价相同。

出于时间复杂度考虑,暴力比较之前的路径是不妥的。

但是我们可以想到一种利用顺序的策略,BFS是逐层搜索,

那么如果每一层都按照当前层的代价从小到大搜索,

那么每搜索到一个点,都会是到这个点(除这层的代价外)最小的代价。

所以后面的点如果当前层代价一样(原本是需要麻烦的比较的情况)就不会更新这个点的状态,

如果当前层代价小就会更新这个状态(高位的优先度高),

所以这种麻烦的情况就不存在了。

实现的话可以开一个滚动的桶,桶里装一个包含某层代价为x的点的队列,从小到大处理即可。

时间复杂度O(n)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90

#include <cstdio>
#include <cstring>
#include <queue>
#include <utility>
using namespace std;
inline int read()
{
	int s = 0; char c; while((c=getchar())<‘0‘||c>‘9‘);
	do{s=s*10+c-‘0‘;}while((c=getchar())>=‘0‘&&c<=‘9‘);
	return s;
}
const int N = 100010;
int n,m,tot,s[N],l[N],l0[N],fr0[N],fr[N],h[N],ans[N],ansp;
struct eg{int dt,w,nx;}e[N*2];
queue<int> q,qa[2][10];
bool inq[N],inq0[N],z[N];
void link(int aa,int bb,int ww)
{
	e[++tot].nx = h[aa]; e[tot].dt = bb; e[tot].w = ww; h[aa] = tot;
	e[++tot].nx = h[bb]; e[tot].dt = aa; e[tot].w = ww; h[bb] = tot;
}
void zerobfs()
{
	q.push(n-1); fr0[n-1] = -1; inq0[n-1] = 1;
	while(!q.empty())
	{
		int hn = q.front(); q.pop();
		for(int nx,pt=h[hn];pt;pt=e[pt].nx)
			if(!e[pt].w&&!inq0[nx=e[pt].dt])
				q.push(nx), inq0[nx] = 1, fr0[nx] = hn, l0[nx] = l0[hn]+1;
	}
}
void bfs()
{
	qa[0][0].push(0);
	memset(s,0x7f,sizeof s); memset(l,0x7f,sizeof l);
	s[0] = 0; l[0] = 0; fr[0] = -1; z[0] = 1;
	int curp = 1;
	while(1)
	{
		curp ^= 1;
		while(!q.empty())
		{
			int hn = q.front(); q.pop();
			if(!inq[hn]) qa[curp][s[hn]].push(hn), inq[hn] = 1;
		}
		bool flag = 1;
		for(int i=0;i<=9;i++)
		{
			while(!qa[curp][i].empty())
			{
				int hn = qa[curp][i].front(); qa[curp][i].pop(); flag = 0;
				for(int nx,pt=h[hn];pt;pt=e[pt].nx)
				{
					nx = e[pt].dt;
					if(l[hn]+1<l[nx]||(l[hn]+1==l[nx]&&(e[pt].w<s[nx])))
					{
						s[nx] = e[pt].w, l[nx] = l[hn]+1, fr[nx] = hn;
						if(!inq[nx]) q.push(nx);
					}
				}
			}
		}
		if(flag) break;
	}
}
int main()
{
	int i,j=0;
	n = read(); m = read();
	for(i=1;i<=m;i++){ int aa = read(), bb = read(); link(aa,bb,read()); }
	zerobfs(); bfs();
	ansp = n-1;
	for(i=0;i<n;i++) if(inq0[i])
		if(l[i]<l[ansp]||(l[i]==l[ansp]&&s[i]<s[ansp])||
		   (l[i]==l[ansp]&&s[i]==s[ansp]&&l[i]+l0[i]<l[ansp]+l0[ansp]))
			ansp = i;
	for(i=ansp;i!=n-1;i=fr0[i]) fr[fr0[i]] = i, s[fr0[i]] = 0;
	bool flag = 0;
	for(i=n-1;i;i=fr[i])
	{
		if(flag||s[i]) putchar(‘0‘+s[i]), flag = 1;
		ans[++j] = i;
	}
	if(!flag) putchar(‘0‘);
	printf("\n%d\n",l[ansp]+l0[ansp]+1); ans[++j] = 0;
	for(i=j;i>1;i--) printf("%d ",ans[i]);
	printf("%d\n",ans[1]);
	return 0;
}

时间: 2024-08-07 16:48:43

Bubble Cup 8 finals G. Run for beer (575G)的相关文章

Bubble Cup X - Finals [Online Mirror]

来自FallDream的博客,未经允许,请勿转载,谢谢. 组了个菜鸡队打cf上的ACM比赛 比较快做完了8题但是菜的抠脚罚时巨多,所以最后被顶到了19名(居然没出首页) 自己的号自从上次疯狂掉分就没动过了,感觉像是红名橙名大佬中的一股清流. A.奇怪的贪心,我写了一发结果挂了,题解见大爷博客 B.dp方程很容易列出来,然后写个矩阵乘法就行了. C.每个点的位置决定了两边的白色小三角形的面积,这个面积是关于位置的一次函数,所以排序之后贪心就行了. D.二分+网络流判定 E.dp方程容易列出,然后换

Bubble Cup X - Finals [Online Mirror] B. Neural Network country 矩阵快速幂加速转移

B. Neural Network country time limit per test 2 seconds memory limit per test 256 megabytes Due to the recent popularity of the Deep learning new countries are starting to look like Neural Networks. That is, the countries are being built deep with ma

Bubble Cup 11 - Finals [Online Mirror, Div. 1] 体验记 + 部分题解

原文链接https://www.cnblogs.com/zhouzhendong/p/CF1045.html 体验?? 陈老爷(cly_none) 带我们飞. 遥遥领先的yzy(yzyyylx) nb . fx 口胡大法好. 哈哈.最后7~8分钟卡常 5974ms 过一道 6000ms 题. 陈老爷切掉了 A D J . yzy 干掉了 C 和 G . fx 半程口胡.中途有事. zzd 菜鸡贡献10多发罚时,导致队伍罚时爆炸.这个菜鸡zzd只 AC 了 I B H ,并在最后7~8分钟把陈老爷

【题解】CF#Bubble Cup X - Finals E-Casinos and travel

天啊我怎么这么蠢……写了一个树形dp,的确发现记录的很多值并没有什么用,然而当时脑子没转过弯来还是写了这个树形dp……虽然能A但就不解释了,总之是个垃圾算法(??д??) #include <bits/stdc++.h> using namespace std; #define maxn 1000000 #define mod 1000000007 #define int long long int n, ans, rec, fa[maxn]; int g[maxn][2], f[maxn][

Bubble Cup 8 finals C. Party (575C)

题意: 给定n个人,分两天晚上去夜总会开派对,要求每天恰好有n/2个人去,且每人去的夜总会各不相同. 每个人对不同的晚上不同的夜总会有不同的满意度,求一个方案使得所有人的满意度之和最大. 夜总会数量=人的数量=n,2<=n<=20,且n是偶数. 0<=每一项满意度<=10^6. 时间限制2s,空间限制4MB. 题解: 在这题上卡了很久… 初看这题觉得是费用流…写完发现图建错了… 然后改成暴力枚举哪些人在第一天晚上去再跑费用流… 每个人只和对应晚上的夜总会连边,然后两天晚上的夜总会再

Bubble Cup 8 finals B. Bribes (575B)

题意: 给定一棵n个点和有向边构成的树,其中一些边是合法边,一些边是非法边, 经过非法边需要1的费用,并且经过之后费用翻倍. 给定一个长为m的序列,问从点1开始按顺序移动到序列中对应点的总费用. 1<=n<=10^5, 1<=m<=10^6 题解: 还是比较水的… 正解是各种方法求LCA,在点上打标记,最后DFS一遍就可以得到答案. 用tarjan求LCA可以做到总复杂度O(n*α)… 我傻傻地见树就剖,强行O(n log n log n)碾过去了… 每次把起点终点之间的路径的经过

Bubble Cup 8 finals H. Bots (575H)

题意: 简单来说就是生成一棵树,要求根到每个叶子节点上的路径颜色排列不同, 且每条根到叶子的路径恰有n条蓝边和n条红边. 求生成的树的节点个数. 1<=n<=10^6 题解: 简单计数. 显然,前n层的边的颜色是任意的,所以第i层就是2^i个点. 对于后n层,可以直接由上一层转移. 因为已经知道上一层合法的个数,那么如果现在每个点扩展两条边, 那么上一层的状态中,某种颜色的个数已经达到n的情况就有一条边不可扩展, 所以要减去2*C(i-1,n). 1 2 3 4 5 6 7 8 9 10 11

Bubble Cup 8 finals D. Tablecity (575D)

题意: (无输入,纯输出题) 一个城市用1000列2行的格子表示,一个小偷藏在城市的某一处. 在每一小时的开始, 在(X, Y)位置的小偷可以移动到 (X - 1, Y), (X + 1, Y),(X - 1, Y - 1), (X - 1, Y + 1), (X + 1, Y - 1), (X + 1, Y + 1)中的任意一个位置. 在每一小时中,警察可以控制搜索两个格子,如果小偷藏在这个格子就会被发现. 请输出一种方案, 使得在2015小时内,对于小偷的初始位置和移动方法的所有可能情况都能

Bubble Cup 8 finals I. Robots protection

题意: 有一个正方形区域, 要求支持两个操作: 1.放置三角形,给定放置方向(有4个方向,直角边与坐标轴平行),直角顶点坐标,边长 2.查询一个点被覆盖了多少次 1<=正方形区域边长n<=5000 1<=询问数<=10^5 保证输入合法,三角形被正方形区域完全包含. 题解: 嗯这是一道数据结构题… 一开始我想起来之前做过但没做出来的一道三角形修改三角形查询的分块题… 然后…GEOTCBRL说,是k-d tree呀,CF上面有标程代码长度限制的… 然而我并不会用k-d tree做这个