3.24考试总结

A 汽油补给

题面:51nod 1288
题解:贪心+单调栈
显然每个点加油加到能到右边第一个比这个点便宜的地方即可

#include<bits/stdc++.h>
using namespace std;
inline void read(int& x)
{
	x = 0; char c = getchar();
	while (!isdigit(c)) c = getchar();
	while (isdigit(c)) x = x * 10 + c - '0', c = getchar();
}
#define maxn 100005
#define ll long long
int n, t, d[maxn], p[maxn], r[maxn];
ll s[maxn], ans;
stack<int> st;
int main()
{
	read(n), read(t);
	for (int i = 1; i <= n; ++i)
	{
		read(d[i]); read(p[i]);
		if (d[i] > t)
		{
			puts("-1");
			return 0;
		}
		s[i] = s[i - 1] + d[i];
	}
	s[n + 1] = s[n];
	for (int i = n; i; --i)
	{
		while (!st.empty() && p[st.top()] > p[i]) st.pop();
		r[i] = (st.empty()) ? n + 1 : st.top();
		st.push(i);
	}
	for (int las = 0, tp, i = 1; i <= n; ++i)//las是当前油量
	{
		tp = min(s[r[i] - 1] - s[i - 1], 1ll * t);//需要油量,和邮箱容量取个min.注意r[i]-1.
		if (tp > las)
		{
			ans += 1ll * (tp - las) * p[i];
			las = tp;
		}
		las -= d[i];
	}
	printf("%lld\n", ans);
	return 0;
}

B 选址

题面:51nod 2558
题解:最短路+贪心
代码实现能力还是太弱了啊
以及吐槽一下这个题解,没有\(LaTex\)还一大段真的是看瞎眼


把原来的题解美化了一下
首先用\(\text{floyd}\)或者\(\text{dijskra}\)求出全源最短路
枚举每一条边\((u,v,w)\)
对于所有点(题解中说是其他点,但这样样例都过不了),按照到\(u\)的距离从大到小排序
枚举\(i\),表示一条路径:\(a_{i}\rightarrow u \rightarrow v \rightarrow \max(a_{1}\sim a_{i-1})\)
其中那个\(\max\)表示\(v\)到那些点的最长距离
这种情况下,最优解必然在路径中点处取得
实现的话后面那个\(\max\)不用每次去扫,直接保存下来就好了(我居然没想到,搞得我还想这复杂度不对啊)
复杂度:\(O(nm\log n)\)


正确性的证明:
Q:为什么对于\(a_{i}\sim a_{n}\)我们只要考虑从\(u\)到这些点?
A:假如经过\(v\)有一条更短的路,从中点到这些点的路径,一定没有中点到\(a_{i}\)的路长
假如从中点先经过\(u\)再到\(a_{1}\sim a_{i-1}\),这些路必定比中点到\(a_{i}\)长,也就是之前已经被考虑过了
由于答案必定是某条路径的中点上,所以我们一定会考虑到这条路径,所以这个算法是正确的

#include<bits/stdc++.h>
using namespace std;
template<typename T>
inline void read(T& x)
{
	x = 0; char c = getchar();
	while (!isdigit(c)) c = getchar();
	while (isdigit(c)) x = x * 10 + c - '0', c = getchar();
}
#define maxn 205
#define maxm 40005
int n, m, tp[maxn], a[maxm], b[maxm], w[maxm];
double dis[maxn][maxn], ans = 1e18, tmp;
inline void floyd()
{
	for (int k = 1; k <= n; ++k)
		for (int i = 1; i <= n; ++i)
			for (int j = 1; j <= n; ++j)
				if (dis[i][k] + dis[k][j] < dis[i][j])
					dis[i][j] = dis[i][k] + dis[k][j];
}

int main()
{
	read(n), read(m);
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= n; ++j) dis[i][j] = 1e18;
	for (int i = 1; i <= n; ++i) dis[i][i] = 0;
	for (int i = 1; i <= m; ++i)
		read(a[i]), read(b[i]), read(w[i]), dis[a[i]][b[i]] = dis[b[i]][a[i]] = w[i];
	floyd();
	for (int i = 1, cnt; i <= m; ++i)
	{
		cnt = 0; tmp = 0;
		for (int j = 1; j <= n; ++j) tp[++cnt] = j;
		sort(tp + 1, tp + cnt + 1, [&](int x, int y) {return dis[a[i]][x] > dis[a[i]][y]; });
		for (int j = 1; j <= cnt; ++j)
		{
			if (tmp >= dis[a[i]][tp[j]] - w[i] && tmp <= dis[a[i]][tp[j]] + w[i]) 
				ans = min(ans, (dis[a[i]][tp[j]] + w[i] + tmp) / 2);//答案是这条路径长度的一半
			tmp = max(tmp, dis[tp[j]][b[i]]);
		}
	}
	printf("%lf\n", ans);
	return 0;
}

C 格子染色

题意:51nod 2564
题解:网络流
咕咕咕

猜你喜欢

转载自www.cnblogs.com/123789456ye/p/12576158.html