
壁纸链接
题目链接:https://atcoder.jp/contests/abc471/tasks
A - Nine or Nein
分别计算、、和,判断其中是否至少有一个结果等于。由于为正整数,不需要处理除数为的情况。满足任意一个条件就输出,否则输出。
void solve(){ int a, b; cin >> a >> b; if(a + b == 9 || a - b == 9 || a * b == 9 || a * 1.0 / b == 9) cout << "Nine" << endl; else cout << "Nein" << endl;}B - Survey Tabulation
题目不区分大小写,所以需要先把每个字符串转换成统一形式,再进行频次统计。代码将所有小写字母映射为对应的大写字母,从而使仅大小写不同的字符串得到相同的键。
使用记录规范化后每个字符串出现的次数,并在插入时同步维护最大频次。设所有字符串的总长度为,时间复杂度为。
void solve(){ int n; cin >> n; int ans = 0; map<string, int> mp; for(int i = 1; i <= n;i++){ string s; cin >> s; for(auto& it : s){ if(it - 'a' >= 0){ it = char('A' + it -'a'); } } mp[s]++; ans = max(mp[s], ans); } cout << ans << endl;}C - Cookies and Greedy Takahashi
将所有负坐标从大到小排序,所有正坐标从小到大排序。这样在任意时刻,负半轴上尚未访问且最靠近当前位置的候选点一定是,正半轴上的对应候选点一定是,其他未访问点都位于这两个边界点的外侧,不可能更近。
因此每一步只需要比较当前坐标到与的距离。若一侧已经取完,就选择另一侧;否则选择距离更小的一侧。两者距离相等时,负坐标更小,按照题目的次级规则应优先选择负侧,所以代码在时移动到。
每个坐标只会被访问一次,排序后的双指针模拟为,加上排序后总时间复杂度为,空间复杂度为。
void solve(){ int n; cin >> n; vector<ll> neg(n), pos(n); for(int i = 1; i <= n;i++){ int x; cin >> x; if(x < 0) neg.push_back(x); else pos.push_back(x); } sort(neg.begin(), neg.end(), greater<ll>()); sort(pos.begin(), pos.end()); ll ans = 0, x = 0; int i = 0, j = 0; int neg_ptr = (int)neg.size(), pos_ptr = (int)pos.size(); while(i < neg_ptr || j < pos_ptr){ if(j == pos_ptr || (i < neg_ptr && x - neg[i] <= pos[j] - x)){ ans += x - neg[i]; x = neg[i]; i++; } else{ ans += pos[j] - x; x = pos[j]; j++; } } cout << ans << endl;}D - Chargers
对于在时刻插入、初始电量为的电池,它达到满电的时刻为
。
在后续时刻,其电量可以写成。对于固定的查询时刻,这个值关于单调不增,因此越小,当前电量越大。问题就转化为动态维护所有电池的,每次取出最小值。
代码使用保存。插入操作加入;取出操作删除集合中的最小元素,并用还原当前电量。如果集合为空则输出。每次操作的时间复杂度为,总时间复杂度为,空间复杂度为。
void solve(){ int Q; ll V; cin >> Q >> V; multiset<ll> st; while(Q--){ int op; cin >> op; if(op == 1){ int t; ll w; cin >> t >> w; st.insert(t + (V - w)); } else{ int t; cin >> t; if(st.empty()) cout << -1 << '\n'; else{ ll val = *st.begin(); st.erase(st.begin()); ll cur = t - val + V; if(cur > V) cur = V; cout << cur << '\n'; } } }}E - Sum of Square of Sum
对于一个选出的大小为的下标集合,将平方展开可得
。
固定一个下标,包含它的大小为的集合共有个,所以所有单项平方的总贡献为
。
固定一对不同下标,同时包含它们的集合共有个。又因为
,
所以所有交叉项的总贡献为
。
我们只需要预处理阶乘和逆阶乘来计算两个组合数,再将两部分贡献相加。预处理与求和的时间复杂度为,空间复杂度为。
void solve(){ ll n, k; cin >> n >> k;
ll s1 = 0, s2 = 0; vector<ll> A(n); for(ll i = 0; i < n;i++){ cin >> A[i]; A[i] %= mod; s1 = (s1 + A[i]) % mod; s2 = (s2 + A[i] * A[i]) % mod; }
vector<ll> fact(n + 1), inv_fact(n + 1); fact[0] = 1; for(ll i = 1; i <= n;i++){ fact[i] = fact[i - 1] * i % mod; }
inv_fact[n] = fast_pow(fact[n], mod - 2, mod); for(ll i = n; i >= 1; i--){ inv_fact[i - 1] = inv_fact[i] * i % mod; }
ll c1 = C(n - 1, k - 1, fact, inv_fact); ll c2 = C(n - 2, k - 2, fact, inv_fact); ll cross = (s1 * s1 % mod - s2 + mod) % mod; ll ans = (c1 * s2 % mod + c2 * cross % mod) % mod;
cout << ans << endl;}模板:
#include <bits/stdc++.h>
using namespace std;using ll = long long;using ull = unsigned long long;#define mod 998244353typedef pair<int, int> pii;typedef pair<ll, ll> pll;
ll fast_pow(ll a, ll b, ll MOD){ ll ans = 1; while(b){ if(b & 1) ans = (ans * a) % MOD; b >>= 1; a = (a * a) % MOD; } return ans;}
vector<ll> get_inverse(ll n, ll MOD){ vector<ll> inverse(n + 1, 0); inverse[1] = 1; for(int i = 2; i <= n;i++){ inverse[i] = MOD - (MOD / i) * inverse[MOD % i] % MOD; } return inverse;}
void solve(){
}
int main(){ ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr); int _ = 1; //cin >> _; while(_--){ solve(); } return 0;}