Codeforces Round 918 (Div. 4)EFG

Codeforces Round 918 (Div. 4)EFG

E. Romantic Glasses(前缀和)

题意

给长度n的数组,选定某个连续的子数列,让里面奇数下标的和等于偶数下标的和。题目下标从1开始

思路

前缀和的骚操作,在计算前缀和的时候,把奇数(或者偶数)下标的数的贡献变为负的。也就是把原数组里面奇数/偶数的数字乘 *-1变成相反数,然后再计算前缀和,这时候如果有某个suml=sumr+1,说明[l,r]的前缀和是0,也就是奇数的和等于偶数的和

代码

#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
vector<string>ans;
void solve() {
	int n; cin >> n;
	vector<long long>sumA(n + 1);
	map<long long, int>mp;
	bool flag = false;
	for (int i = 1, a; i <= n; i++) {
		cin >> a;
		if ((i & 1) == 1)a *= -1;
		sumA[i] = sumA[i - 1] + a;
		mp[sumA[i]]++;
		if (mp[sumA[i]] >= 2||!sumA[i])flag = true;
	}
	if (flag)ans.push_back("YES");
	else ans.push_back("NO");
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int _; _ = 1;
	cin >> _;
	while (_--)	solve();
	for (auto x : ans)cout << x << endl;
	return 0;
}

F. Greetings(思维)

题意

有n个人,每个人都有起点和终点,到了终点之后就会停下,每个人的速度都一样。如果两个人在路上相遇了,就会打招呼,问总共打招呼的次数

思路

只有 ai < aj < bj < bi 的时候,才会相遇,其实也就是根据a来排序下标之后,在b中,下标逆序对的数量

比如只看i和j,根据起点a来排序之后就是i,j,但是看终点b的数组中,顺序是j,i,那么它们就会相遇

暴力枚举肯定超时,所以要用归并排序的时候求逆序对的方法来求

代码

#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
vector<long long>ans;
long long cnt = 0;
struct interval {
	int l, r;
};
vector<interval>help, v;

bool cmp(interval& i1, interval& i2) {
	return i1.l < i2.l;
}

void mergeSort(int l, int r) {
	if (l == r)return;
	int mid = (l + r) >> 1;
	mergeSort(l, mid);
	mergeSort(mid + 1, r);
	int a = l, b = mid + 1, i = l;
	while (a <= mid && b <= r) {
		if (v[a].r <= v[b].r) {
			help[i++] = v[a++];
		}
		else {
			cnt += mid + 1 - a;
			help[i++] = v[b++];
		}
	}
	while (a <= mid) {
		help[i++] = v[a++];
	}
	while (b <= r) {
		help[i++] = v[b++];
	}
	for (int j = l; j < i; j++) {
		v[j] = help[j];
	}
}

void solve() {
	int n; cin >> n;
	cnt = 0;
	v.resize(n);
	help.resize(n);
	for (int i = 0; i < n; i++) {
		cin >> v[i].l >> v[i].r;
	}
	// 根据左端点排序,然后看右端点的逆序对
	sort(v.begin(), v.end(), cmp);
	mergeSort(0, n - 1);
	ans.push_back(cnt);
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int _; _ = 1;
	cin >> _;
	while (_--)	solve();
	for (auto x : ans)cout << x << endl;
	return 0;
}

G. Bicycles(Dijkstra、分层图)

题意

给无向图,每个点有一个自行车,自行车有速度系数,然后当前每个边的边权就变成了速度系数 * 距离,随时可以换车,求这种情况下去节点n的最短路

思路

定义dis[i][j], i 表示到节点 i , j 表示到这个节点用编号为 j 的车,然后跑Dijkstra

代码

#include<bits/stdc++.h>
#define endl '\n'
#define INF 0x3f
using namespace std;
typedef tuple<long long, int, int> TIII;	// 距离,编号,当前自行车的编号
vector<long long>ans;
const int N = 1e3 + 5;
int s[N], head[N], vis[N][N], cnt, n, m;
long long dis[N][N];

struct edge {
	int to, nex, w;
}e[2 * N];

void addEdge(int x, int y, int w) {
	cnt++;
	e[cnt] = { y,head[x],w };
	head[x] = cnt;
}

void init() {
	cnt = 0;
	cin >> n >> m;
	memset(head, -1, sizeof(head));
	memset(dis, INF, sizeof(dis));
	memset(vis, 0, sizeof(vis));
	for (int i = 1, u, v, w; i <= m; i++) {
		cin >> u >> v >> w;
		addEdge(u, v, w);
		addEdge(v, u, w);
	}
	for (int i = 1; i <= n; i++) {
		cin >> s[i];
	}
}

long long dijkstra() {
	dis[1][1] = 0;
	priority_queue<TIII, vector<TIII>, greater<TIII>>q;
	q.push({ 0,1,1 });
	while (!q.empty()) {
		auto [d, u, id] = q.top();
		q.pop();

		if (vis[u][id])continue;
		vis[u][id] = 1;

		// 如果有更好的,直接换
		if (s[u] < s[id]) {
			q.push({ d,u,u });
			continue;
		}

		for (int j = head[u]; j != -1; j = e[j].nex) {
			int v = e[j].to;
			if (dis[v][id] > d + 1ll * e[j].w * s[id]) {
				dis[v][id] = d + 1ll * e[j].w * s[id];
				q.push({ dis[v][id],v,id });
			}
		}
	}
	long long res = LLONG_MAX;
	for (int i = 1; i <= n; i++) {
		res = min(res, dis[n][i]);
	}
	return res;
}

void solve() {
	init();
	ans.push_back(dijkstra());
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int _; _ = 1;
	cin >> _;
	while (_--)	solve();
	for (auto x : ans)cout << x << endl;
	return 0;
}
posted @ 2025-04-26 21:43  zombieee  阅读(12)  评论(0)    收藏  举报