
壁纸链接
题目链接:https://atcoder.jp/contests/abc473/tasks
A - Second Half Sum
因为为偶数,序列后半部分的下标范围为到。读入序列时只累加满足的元素即可。时间复杂度为,额外空间复杂度为。
void solve(){ int n; cin >> n; int sum = 0; for(int i = 1; i <= n;i++){ int x; cin >> x; if(i >= n / 2 + 1) sum += x; } cout << sum << endl;}B - Old Maid
对于值为的卡片,设其出现次数为。每次操作会删除两张相同的卡片,所以最终剩余数量只由的奇偶性决定:偶数张可以全部配对删除,奇数张会剩下一张。
因此先统计每个整数的出现次数,再将所有出现次数为奇数的整数值累加到答案中。使用统计时,时间复杂度为,空间复杂度为。
void solve(){ int n; cin >> n; map<int, int> mp; for(int i = 1; i <= n;i++){ int x; cin >> x; mp[x]++; } int ans = 0; for(auto it : mp){ if(it.second & 1) ans += it.first; } cout << ans << endl;}C - Change Schools
先统计每个班级当前的人数,并求出全局最大人数。如果选择第个班级,加入后该班人数会从变为,要使其不小于其他所有班级的人数,必须满足。
因此合法班级恰好是当前人数等于或的班级。人数为时加入后会成为新的最大值,人数为时加入后会追平当前最大值;更少的班级加入一人后仍小于。遍历所有班级统计这两类即可。时间复杂度为,空间复杂度为。
void solve(){ int n, k; cin >> n >> k; vector<int> a(n + 1, 0); vector<vector<int>> b(k + 1); for(int i = 1; i <= n;i++){ cin >> a[i]; b[a[i]].push_back(i); } int ma = 0; ll cnt = 0; for(int i = 1; i <= k;i++) ma = max(ma, (int)b[i].size()); for(int i = 1; i <= k;i++){ if((int)b[i].size() == ma || (int)b[i].size() == ma - 1) cnt++; } cout << cnt << endl;}D - Coefficient Stair
需要枚举所有满足
的非负整数序列。使用深度优先搜索依次确定。当正在确定且剩余权值为时,的取值范围为到;选择后递归处理下一维,并将剩余权值更新为。
到达最后一维时,已被剩余权值唯一确定。只有能被整除时才存在合法取值,此时输出整个序列。这样不会遗漏方案,也不会重复输出。
为了保证字典序,DFS在每一维都按从小到大的顺序枚举当前值。较前位置的值更小的序列会先完成整棵子树,因此最终输出顺序自然为字典序。时唯一答案为,可以直接输出。空间复杂度为递归深度;时间复杂度与DFS访问的状态数以及输出量成正比,而输出个序列本身至少需要的时间。
int n, k;vector<int> a;
void dfs(int x, int rest){ if(x == n){ if(rest % n == 0){ a[n] = rest / n;
for(int i = 1; i <= n;i++){ cout << a[i] << ' '; } cout << '\n'; } return; } for(int i = 0; i <= rest / x;i++){ a[x] = i; dfs(x + 1, rest - x * i); }}
void solve(){ cin >> n >> k; a.resize(n + 1); if(n == 1) {cout << k << '\n'; return;} dfs(1, k);}E - K-Divisible Subarrays
将原序列任意分段后,得分只来自区间和能被整除的段。所有未被选入这些得分段的位置都可以单独分段或并入相邻的无贡献段,不会降低已有得分。因此问题等价于选择尽可能多的、两两不相交且区间和能被整除的非空子数组。
定义前缀和模的余数为,并令。区间的元素和能被整除,当且仅当。再定义表示前个元素中最多能选择多少个合法且互不相交的子数组,则有两种转移:不以结尾时继承;选择某个以结尾的合法区间时,贡献为。
直接枚举所有会达到。代码用维护所有已经处理过且的位置中最大的,于是
。
计算完后,再用它更新。初始状态对应空前缀。使用时,期望时间复杂度为,空间复杂度为。
void solve(){ int n, k; cin >> n >> k; vector<int> a(n + 1, 0); for(int i = 1; i <= n;i++) cin >> a[i]; unordered_map<ll, int> best; best[0] = 0; ll pre = 0; int dp = 0; for(int i = 1; i <= n;i++){ pre = (pre + a[i]) % k; int ndp = dp; if(best.count(pre)) ndp = max(ndp, best[pre] + 1); dp = ndp; if(best.count(pre)) best[pre] = max(best[pre], dp); else best[pre] = dp; } cout << dp << '\n';}模板:
#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;}