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;
}

浙公网安备 33010602011771号