目录
D. Cycle
这道题就是个 01 最短路,直接从 1 开始 bfs 看能不能回到 1
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5 + 5, INF = 1e18;
struct node
{
int u, s;
};
int T, n, m, cnt, ans, vis[N];
vector<int> G[N];
queue<node> q;
signed main()
{
cin >> n >> m;
for (int i = 1; i <= m; i ++)
{
int u, v;
cin >> u >> v;
G[u].push_back(v);
}
q.push({1, 0}), vis[1] = 1;
while (!q.empty())
{
node t = q.front(); q.pop();
for (auto x : G[t.u])
{
if (x == 1)
{
cout << t.s + 1;
return 0;
}
if (vis[x] == 1)
continue;
vis[x] = 1;
q.push({x, t.s + 1});
}
}
cout << -1;
return 0;
}
D. Cycle(改)
如果这道题边权不是 1,思路是:
(1) 一个环从 1 --> 1 变成 1 --> k,k --> 1。k 是环上一点
(2)求 1 到 k 的最短路和 k 到 1 的最短路,相加就是答案
(3)因为两个最短路都是以 1 为原点,所以第二个最短路在反图上求
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5 + 5, INF = 1e18;
struct node
{
int v, w;
};
int T, n, m, cnt, ans, d1[N], d2[N], vis[N];
vector<node> G1[N], G2[N];
priority_queue<pair<int, int> > pq;
void dj1()
{
for (int i = 1; i <= n; i ++)
d1[i] = 1e9;
for (int i = 1; i <= n; i ++)
vis[i] = 0;
d1[1] = 0;
pq.push({0, 1});
while (!pq.empty())
{
auto t = pq.top(); pq.pop();
int u = t.second;
if (vis[u] == 1)
continue;
vis[u] = 1;
for (auto x : G1[u])
{
int v = x.v, w = x.w;
if (d1[v] > d1[u] + w)
{
d1[v] = d1[u] + w;
pq.push({-d1[v], v});
}
}
}
}
void dj2()
{
for (int i = 1; i <= n; i ++)
d2[i] = 1e9;
for (int i = 1; i <= n; i ++)
vis[i] = 0;
d2[1] = 0;
pq.push({0, 1});
while (!pq.empty())
{
auto t = pq.top(); pq.pop();
int u = t.second;
if (vis[u] == 1)
continue;
vis[u] = 1;
for (auto x : G2[u])
{
int v = x.v, w = x.w;
if (d2[v] > d2[u] + w)
{
d2[v] = d2[u] + w;
pq.push({-d2[v], v});
}
}
}
}
signed main()
{
cin >> n >> m;
for (int i = 1; i <= m; i ++)
{
int u, v;
cin >> u >> v;
G1[u].push_back({v, 1}), G2[v].push_back({u, 1});
}
dj1();
dj2();
ans = 1e9;
for (int i = 2; i <= n; i ++)
ans = min(ans, d1[i] + d2[i]);
if (ans == 1e9)
cout << -1;
else
cout << ans;
return 0;
}
E. Max × Sum
(1)把 a 和 b 数组捆绑起来,用 pair 存。
(2)对 a 进行从小到大排序,那么 max a [ i ] 就变成了我枚举的值,变量就只剩下对可选择的 b [ i ] 选 k 个求和。此时小于 a [ i ] 的 pair 对中的 b [ i ] 都是可以选择的。
(3)枚举的 a [ i ] 是肯定选的,那么捆绑的 b [ i ] 也一定选,所以就是在前 i - 1 个里面选 k - 1 个。
(4)用优先队列动态维护前 k - 1 个最小值之和,对于新的 b [ i ] 可以通过弹掉队首来替换
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5 + 5, INF = 1e18;
int T, n, k, tot, ans;
pair<int, int> a[N];
priority_queue<int> pq;
signed main()
{
cin >> T;
while (T --)
{
cin >> n >> k;
for (int i = 1; i <= n; i ++)
cin >> a[i].first;
for (int i = 1; i <= n; i ++)
cin >> a[i].second;
while (!pq.empty())
pq.pop();
sort(a + 1, a + n + 1);
tot = 0, ans = INF;
for (int i = 1; i < k; i ++)
pq.push(a[i].second), tot += a[i].second;
for (int i = k; i <= n; i ++)
{
// 写法一
tot += a[i].second;
ans = min(ans, a[i].first * tot);
pq.push(a[i].second);
tot -= pq.top();
pq.pop();
// 写法二
int res = a[i].first * (a[i].second + tot);
ans = min(ans, res);
// !只要涉及到 top 和 pop 操作的一定要看队列是否为空 !
// 题中的 k 是可能为 1 的, 那么此时队列就为空
if (!pq.empty() && a[i].second < pq.top())
{
tot -= pq.top();
tot += a[i].second;
pq.pop();
pq.push(a[i].second);
}
}
cout << ans << '\n';
}
return 0;
}