前面两道阅读理解直接跳过。
C - Σ
大意
给定序列,求中所有数的和,但要排除中出现的数字。
思路
首先,算出后减去中出现过的数即可。
注意要对去重,或者使用set。
代码
#include<iostream>
#include<vector>
#include<set>
using namespace std;
typedef long long LL;
int main(){
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
LL n, k;
cin >> n >> k;
vector<LL> a(n);
for(auto &x: a) cin >> x;
set<LL> b(a.begin(), a.end());
LL ans = k * (k + 1) / 2;
for(auto &x: b){
if(x <= k) ans -= x;
}
cout << ans << endl;
return 0;
}
D - Gomamayo Sequence
大意
给定一个字符串,对第位取反需要 的代价。
定义一个好的字符串,当且仅当只有一个相邻位置上的数字是相同的。
问将字符串变成好的字符串的最小代价。
思路
长度为的好串只有个,我们可以枚举所有的情况。
我们枚举相邻数字相同的位置,然后计算变成和这两种情况的代价,取最小值。
可以设前缀和与后缀和数组,事先计算所有前缀和后缀变成和的代价,通过前缀代价+后缀代价,就可以得到当前枚举的情况的代价。
代码
#include<iostream>
#include<vector>
using namespace std;
#define int long long
typedef long long LL;
const int INF = 1e18 + 10;
template<class T>
T min(T a, T b, T c){
return min(min(a, b), c);
}
signed main(){
LL n;
string s, t="01";
cin >> n >> s;
vector<LL> c(n);
for(auto &x: c) cin>>x;
vector<LL> pre1(n), pre2(n), suf1(n), suf2(n);
for(int i = 0; i < n; i++){
pre1[i] = (s[i] == t[i & 1]? c[i]: 0) + (i > 0? pre1[i - 1]: 0);
pre2[i] = (s[i] == t[~i & 1]? c[i]: 0) + (i > 0? pre2[i - 1]: 0);
}
for(int i = n - 1; i >= 0; i--){
suf1[i] = (s[i] == t[i & 1]? c[i]: 0) + (i < n - 1? suf1[i + 1]: 0);
suf2[i] = (s[i] == t[~i & 1]? c[i]: 0) + (i < n - 1? suf2[i + 1]: 0);
}
LL ans = INF;
for(int i = 0; i < n - 1; i++){
ans = min(ans, pre1[i] + suf2[i + 1], pre2[i] + suf1[i + 1]);
}
cout << ans << endl;
return 0;
}
E - Paint
大意
有一个的网格,初始所有格子都是颜色0,给定一些操作,每个操作是将一行或一列涂上指定颜色。执行完所有操作后,输出每种颜色的格子各有几个。(后涂的会覆盖先涂的)
思路
朴素的做法,最后统计颜色,时间复杂度。
考虑到每次操作都是对一行或一列涂色,其涂的格子数是已知的,所以可以直接累计结果。
但这样的问题是,由于后效性,后面的操作会影响到前面的结果,颜色会覆盖,导致先前涂的颜色数量可能会变少。
不妨将操作反过来考虑,先考虑最后一次操作,再考虑前一个操作,那么后考虑的操作不会影响先考虑的操作。
因此我们对操作倒过来考虑,每次操作所涂的格子数。格子数的求法比较简单。当然还要维护某一列和某一行是否被涂过,后涂的操作是无效的。
注意颜色0也要算。
代码
#include<iostream>
#include<vector>
#include<array>
#include<algorithm>
#include<numeric>
using namespace std;
const int N=2e5+8;
#define int long long
typedef pair<int, int> PII;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int h, w, m;
cin >> h >> w >> m;
vector<array<int, 3>> op(m);
for(auto &[t, a, x]: op){
cin >> t >> a >> x;
a--;
}
vector<int> cnt(N, 0), used_row(h, 0), used_col(w, 0);
int row = h, col = w;
reverse(op.begin(), op.end());
for (auto& [t, a, x]: op) {
if (t == 1) {
if (used_row[a]) continue;
used_row[a] = 1;
row--;
cnt[x] += col;
} else {
if (used_col[a]) continue;
used_col[a] = 1;
col--;
cnt[x] += row;
}
}
cnt[0] += h * w - accumulate(cnt.begin(), cnt.end(), 0ll);
vector<PII> ans;
for (int i = 0; i < N; i++)
if (cnt[i])
ans.emplace_back(i, cnt[i]);
cout << ans.size() << endl;
for (auto& [i, c]: ans) cout << i << " " << c << endl;
return 0;
}