AtCoder Beginner Contest 187
导读:
简单的题目,只说明题意,或者直接说明结论
下面的难题,会做详细的解释和证明
立个flag,在座的大佬们做个见证:一个月刷60场ABC,现在2021/6/24,第九天,已打卡十三场。
A - Large Digits
输出两个三位数每一位的数字和中较大的一个
void work()
{
int a, b; cin >> a >> b;
cout << max(a % 10 + a / 10 % 10 + a / 100, b % 10 + b / 10 % 10 + b / 100) << endl;
}
B - Gentle Pairs
横坐标之差大于等于纵坐标之差
void work()
{
int n; cin >> n;
int a[1010], b[1010];
for (int i = 1; i <= n; i ++ )
cin >> a[i] >> b[i];
int ans = 0;
for (int i = 1; i < n; i ++ )
for (int j = i + 1; j <= n; j ++ )
{
if (abs(a[i] - a[j]) >= abs(b[i] - b[j]))
ans ++;
}
cout << ans << endl;
}
C - 1-SAT
问是已经出现了加!和不加!同一个字符串。
拿到这题第一印象就是trie树,结果,算了,就这一点,直接暴力就完事了。
void work()
{
int n; cin >> n;
unordered_map<string, bool> mp;
while (n -- )
{
string s; cin >> s;
if (s[0] == '!')
{
string t = s.substr(1);
if (mp.count(t))
{
cout << t << endl;
return;
}
mp[s] = true;
}
else
{
if (mp.count("!" + s))
{
cout << s << endl;
return;
}
mp[s] = true;
}
}
cout << "satisfiable" << endl;
}
D - Choose Me
思维题啊,我欠缺的就是这种题目
如果再当前位置做演讲,结果就是B加上a+b,如果不做演讲,那就是A加上a
题目让我们输出使B成绩大于A的最小演讲次数。
假设一开始一次演讲都没做,也就是说sum为n个a的和,这也是A与B之间的差距,我们将这个sum定义为A与B之间的分数差距,那么我们每做一次演讲,首先本来给A的a,会变成B的投票,先-x,差距小了x,然后,因为票a+b都投给了B,所以,A的差距优惠减去(a+b)了。
所以我们贪心的每次减去最大的x+x+y,知道sum小于0,就是A的成绩小于B的时候了。
#include <bits/stdc++.h>
using namespace std;
using ll = int64_t;
int main()
{
ll n; cin >> n;
ll sum = 0;
vector<ll> v;
for (int i = 0; i < n; i ++ )
{
ll x, y; scanf("%lld%lld", &x, &y);
sum += x;
v.push_back(x + x + y);
}
sort(v.begin(), v.end());
while (sum >= 0)
{
sum -= v.back();
v.pop_back();
}
cout << n - v.size() << endl;
return 0;
}
E - Through Path
这题最关键的地方就是对a能够到达且不会通过b的地方+x,
我们可以想到a能到达的地方,但是b不能到达的地方起始就是b这个点,将树分为两部分,看a在下部,那就是a的这颗子树全都加x,否则剩余部分加x从b这个位置-x。
运用的就是树形前缀和
#include <bits/stdc++.h>
using namespace std;
using ll = int64_t;
const int N = 200010;
int n;
ll sum[N];
int main()
{
cin >> n;
//存图
vector<vector<int>> v(n + 1);
vector<pair<int, int> > edge(n + 1);
for (int i = 1; i < n; i ++ )
{
int a, b; scanf("%d%d", &a, &b);
v[a].push_back(b);
v[b].push_back(a);
edge[i] = {a, b};
}
// 宽搜给每个点一个深度
queue<int> q;
q.push(1);
vector<int> depth(n + 1, -1);
depth[1] = 1;
while (!q.empty())
{
int x = q.front(); q.pop();
for (int y : v[x])
{
if (depth[y] != -1) continue;
depth[y] = depth[x] + 1;
q.push(y);
// printf("x = %d, depth[x] = %d, y = %d, depth[y] = %d\n", x, depth[x], y, depth[y]);
}
}
// for (int i = 1; i <= n; i ++ ) cout << depth[i] << " "; cout << endl;
int Q; cin >> Q;
while (Q -- )
{
int t, e, x; scanf("%d%d%d", &t, &e, &x);
int a = edge[e].first, b = edge[e].second;
if (t == 2) swap(a, b);
// cout << a << " " << b << endl;
if (depth[a] < depth[b]) sum[1] += x, sum[b] -= x;
else sum[a] += x;
// for (int i = 1; i <= n; i ++ ) cout << sum[i] << " "; cout << endl;
}
vector<ll> ans(n + 1);
ans[1] = sum[1];
q.push(1);
vector<bool> vis(n + 1, false);
vis[1] = true;
while (q.size())
{
int x = q.front();
q.pop();
for (int y : v[x])
{
if (vis[y]) continue;
ans[y] = ans[x] + sum[y];
vis[y] = true;
q.push(y);
}
}
for (int i = 1; i <= n; i ++ )
printf("%lld\n", ans[i]);
return 0;
}