ABC352 编程笔记
题意:输入,四个数
a
,
b
,
c
,
d
a,b,c,d
a,b,c,d,若
d
d
d 在
c
,
d
c,d
c,d 之间,则输出 Yes
,否则输出 No
。
正解:直接判断。
#include <bits/stdc++.h>
//#define int long long
using namespace std;
void solve()
{
int a,b,c,d;
cin >> a >> b >> c >> d;
if (d >= b && d <= c || d >= c && d <= b) cout << "Yes";
else cout << "No";
}
signed main()
{
int TTT;
// cin >> TTT;
TTT = 1;
while (TTT--) solve();
return 0;
}
题意:有两个字符串
S
,
T
S,T
S,T,找出
T
T
T 里所有
S
S
S 的字符的下标,并输出。
正解:模拟。
#include <bits/stdc++.h>
//#define int long long
using namespace std;
void solve()
{
string s,t;
cin >> s >> t;
for (int i = 0,j = 0;i < t.size();i++)
if (s[j] == t[i]) cout << i+1 << ' ',j++;
}
signed main()
{
int TTT;
// cin >> TTT;
TTT = 1;
while (TTT--) solve();
return 0;
}
题意:给出所有人的肩膀的海拔高度和头部的海拔高度,求出所有人叠高高后的最高海拔高度。
正解:贪心。
#include <bits/stdc++.h>
#define int long long
using namespace std;
struct node
{
int a,b;
}a[200010];
bool cmp(node a,node b)
{
if (a.a == b.a) return a.b > b.b;
return a.a > b.a;
}
void solve()
{
int n,sum = 0,mx = -1e18;
cin >> n;
for (int i = 1;i <= n;i++) cin >> a[i].a >> a[i].b,sum += a[i].a;
sort(a+1,a+n+1,cmp);
for (int i = 1;i <= n;i++)
{
int now = sum - a[i].a + a[i].b;
mx = max(mx,now);
}
cout << mx;
}
signed main()
{
int TTT;
// cin >> TTT;
TTT = 1;
while (TTT--) solve();
return 0;
}
题意:给你一个
1
1
1 到
n
n
n 的排列
p
p
p,找到一个长为
k
k
k 的子序列,满足子序列中元素重排后构成公差为
1
1
1 的等差数列,求子序列的最小跨度。
正解:用 p i p_i pi 表示 i i i 这个数在原数组里的下标,则只需算 min ( p k − p 1 , p k + 1 − p 2 , p k + 2 − p 3 , … , p n − p n − k + 1 ) \min(p_k-p_1,p_{k+1}-p_2,p_{k+2}-p_3,\dots,p_n-p_{n-k+1}) min(pk−p1,pk+1−p2,pk+2−p3,…,pn−pn−k+1),并且让 p a − p a − k + 1 > 0 p_a-p_{a-k+1}>0 pa−pa−k+1>0。
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n,k;
int a[200010],b[200010];
void solve()
{
cin >> n >> k;
for (int i = 1;i <= n;i++) cin >> a[i],b[a[i]] = i;
set <int> id; //记录选取的数字的下标,自动排序
for (int i = 1;i <= k;i++) id.insert(b[i]);
int ans = *id.rbegin() - *id.begin();
for (int i = k+1;i <= n;i++)
{
id.erase(b[i-k]);
id.insert(b[i]);
ans = min(ans,*id.rbegin() - *id.begin());
}
cout << ans;
}
signed main()
{
int TTT;
// cin >> TTT;
TTT = 1;
while (TTT--) solve();
return 0;
}
题意:
给你一个加权无向图 G G G,有 N N N 个顶点,编号为 1 1 1 至 N N N。最初, G G G 没有边。
您将执行 M M M 次操作来为 G G G 添加边。第 i i i 次操作 ( 1 ≤ i ≤ M ) (1\le i\le M) (1≤i≤M) 如下:
- 给你一个由 K i K_i Ki 个顶点组成的顶点子集 S i = A i , 1 , A i , 2 , … , A i , K i S_i={A_{i,1}, A_{i,2},\dots,A_{i,K_i}} Si=Ai,1,Ai,2,…,Ai,Ki。对于每一对 u , v u,v u,v,即 u , v ∈ S i u,v∈S_i u,v∈Si 和 u < v u<v u<v,在顶点 u u u 和 v v v 之间添加一条边,权重为 C i C_i Ci。
执行所有 M M M 操作后,确定 G G G 是否相连。如果是,求 G G G 最小生成树中各条边的总重。
正解:
用 Kruskal 的原理:每次添加最小的边。把所有的边权种类从小到大排序后每次添加最小的边。
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n,m;
pair <int,vector<int> > a[666666];
int fa[666666];
int find(int x) {return x == fa[x] ? x : fa[x] = find(fa[x]);}
int merge(int x,int y)
{
int fx = find(x),fy = find(y);
if (fx == fy) return 0;
fa[fy] = fx;
return 1;
}
bool cmp(pair<int,vector<int> > c,pair<int,vector<int> > b) {return c.first < b.first;}
void solve()
{
cin >> n >> m;
for (int i = 1;i <= n;i++) fa[i] = i;
for (int i = 1;i <= m;i++)
{
int k,c;
cin >> k >> c;
vector <int> v(k);
for (int i = 0;i < k;i++) cin >> v[i];
a[i] = {c,v};
}
sort(a+1,a+m+1,cmp);
int ans = 0;
for (int i = 1;i <= m;i++)
{
int c = a[i].first;
vector <int> v;
for (int j = 0;j < a[i].second.size();j++) v.push_back(a[i].second[j]);
int id = v[0];
for (int j = 0;j < v.size();j++)
if (merge(id,v[j]))
ans += c;
}
for (int i = 1;i <= n;i++)
if (find(1) != find(i))
{
cout << "-1\n";
return ;
}
cout << ans << '\n';
}
signed main()
{
int TTT;
// cin >> TTT;
TTT = 1;
while (TTT--) solve();
return 0;
}