2024-05-06-ABC352
ABC352讲解
A - AtCoder Line
题意:铁路上有N个车站,编号为1,2,3,...,N,有趟列车从1号车站,依次停靠2,3,...,N号站,有另一趟列车从N号车站反过来行驶。现在高桥要从X站前往Y站,问他坐的车是否会在Z站停车。
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, x, y, z;
cin >> n >> x >> y >> z;
if (x > y) {
swap(x, y);
}
if (x <= z and z <= y) {
cout << "Yes\n";
} else {
cout << "No\n";
}
return 0;
}
B - Typing
题意:给定正确的字符串和实际输入的字符串,输出实际输入的字符串中正确输入的字符的下标。
#include <bits/stdc++.h>
using namespace std;
int main() {
string s, t;
cin >> s >> t;
for (int i = 0, j = 0; j < t.size(); j++) {
if (s[i] == t[j]) {
cout << j + 1 << ' ';
i++;
}
}
return 0;
}
C - Standing On The Shoulders
题意:给定 n 个巨人从肩膀到地面的高度和从头到地面的高度,将 n 个巨人堆成一个“柱子”,处于高处的巨人站在身下的巨人的肩膀上。依次放完,问最后放置的巨人的头离地最高能够有多高。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int main() {
int n;
cin >> n;
vector a(n, 0), b(n, 0);
int mx = 0;
ll sum = 0;
for (int i = 0; i < n; i++) {
cin >> a[i] >> b[i];
sum += a[i];
mx = max(mx, b[i] - a[i]);
}
cout << sum + mx;
return 0;
}
D - Permutation Subsequence
题意:从给定的大小为 n 的排列 p 中抽出 k 个来,这 k 个元素经过排序后需要是公差为 1 的等差数列,最小化这 k 个数中的最大下标和最小下标的差,输出这个最小值。
解法:滑动窗口枚举k个元素的区间。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, k;
cin >> n >> k;
vector a(n, 0);
for (int i = 0; i < n; i++) {
int x;
cin >> x;
x--;
a[x] = i;
}
int ans = INT_MAX;
set<int> st;
for (int i = 0; i < n; i++) {
st.insert(a[i]);
if (i >= k - 1) {
ans = min(ans, *st.rbegin() - *st.begin());
st.erase(a[i - k + 1]);
}
}
cout << ans;
return 0;
}
E - Clique Connect
题意:给定 n 个点的带权无向图,和 m 次操作,每次操作给定点数 k 和边权 c,然后将给定的 k 个点两两加边,边权为 c 。最后求最小生成树的边权。
解法:一个裸的kruscal最小生成树。
#include<bits/stdc++.h>
#define rep(i,n) for(int i=0;i<(int)n;i++)
#define ll long long
#define fi first
#define se second
#define pb push_back
using namespace std;
int n,m;
ll ans,cnt;
pair<ll,vector<int> > v[200005];
int fa[200005];
int findfa(int x)
{
if(fa[x]==x) return x;
else return fa[x]=findfa(fa[x]);
}
int main()
{
cin>>n>>m;
rep(i,m)
{
int k;
cin>>k>>v[i].fi;
rep(j,k)
{
int x;
cin>>x;
v[i].se.pb(x);
}
}
rep(i,n) fa[i+1]=i+1;
sort(v,v+m);
rep(i,m)
{
rep(j,v[i].se.size())
{
if(!j) continue;
int fx=findfa(v[i].se[j]),fy=findfa(v[i].se[j-1]);
if(fx!=fy)
{
ans+=v[i].fi;
fa[fx]=fy;
cnt++;
}
}
}
if(cnt!=n-1) cout<<-1;
else cout<<ans;
return 0;
}
F - Estimate Order
题意:有 n 个人的具体排名未知。已知这 n 个人的排名各不相同,以及 m 个条件,每个条件是 a 和 b 的排名差。需要通过已知信息求出可以确定排名的人的排名。
解法:首先处理出所有的连通块,对于每一个连通块,连通块中一个的位置确定了,其他的位置都确定了。我们在给每一个连通块做一个mask,表示他们需要占领的位置,比如mask是10011,表示连通块内有三个元素,他们可以是1、4、5名,也可以是2、5、6名等等,要注意处理mask的时候要存储好这个mask内每一个1的实际的人的下标。然后就是暴力dfs每一个连通块,把每一个块的mask往一开始为空的总mask里塞,对于每一个连通块,记录他们在有几种不同位置的合法方案,如果最后一个连通块的合法方案数唯一,那么这个连通块内的所有人的排名都是唯一的。
需要注意的是,如果把大小为1的连通块也放进去,那么整体时间复杂度会退化到O(n!),不放的话,时间复杂度就是O((n/2)!),是可以通过的,就是最后需要特别处理一下大小为1的块,即不受任何约束的人。
#include<bits/stdc++.h>
#define rep(i,n) for(int i=1;i<=(int)n;i++)
#define For(i,n) for(int i=0;i<(int)n;i++)
#define ll long long
#define fi first
#define se second
#define pb push_back
#define pii pair<int,int>
using namespace std;
vector<pair<int, int> > v[20];
int n, m, single, nsingle;
bool vis[20];
int sum[20];
vector<pii > p[20];
vector<pii > masks;
int pos[20], ans[20];
set<int> lmask;
bool flag = 0;
void dfs(int x, int dep, int id) {
vis[x] = 1;
p[id].pb({dep, x});
for (auto y : v[x]) {
if (!vis[y.fi]) {
dfs(y.fi, dep + y.se, id);
}
}
}
int dfs2(int x, int mask) {
if (x == (int)masks.size()) {
lmask.insert(mask);
return 1;
}
int tmp = masks[x].fi, f = 0;
rep(i, n) {
if ((tmp << i) >= (1 << (n + 1))) break;
if ((tmp << i)&mask) continue;
int t = dfs2(x + 1, mask | (tmp << i));
if (t) {
f = 1;
if (sum[x] == 0) {
pos[x] = i;
sum[x]++;
} else {
if (pos[x] != i) sum[x]++;
}
}
}
return f;
}
int main() {
cin >> n >> m;
rep(i, m) {
int x, y, c;
cin >> x >> y >> c;
v[x].pb({y, -c});
v[y].pb({x, c});
}
int k = 0;
rep(i, n) {
if (!vis[i]) {
dfs(i, 0, ++k);
if (p[k].size() >= 2) {
sort(p[k].begin(), p[k].end());
int pls = -p[k][0].fi, mask = 0;
for (auto it : p[k]) mask = mask | (1 << (it.fi + pls));
masks.pb({mask, k});
} else {
single++;
nsingle = i;
}
}
}
dfs2(0, 0);
For(i, masks.size()) {
if (sum[i] == 1) {
int tmp = masks[i].fi << pos[i], k = 0;
rep(j, n) {
if (tmp & (1 << j)) {
ans[p[masks[i].se][k++].se] = j;
}
}
}
}
if (single == 1 && lmask.size() == 1) {
int tmp = *lmask.begin();
rep(i, n) if (!((1 << i)&tmp)) {
ans[nsingle] = i;
break;
}
}
rep(i, n) {
if (!ans[i]) cout << "-1 ";
else cout << ans[i] << " ";
}
return 0;
}