codeforces round 790
790
A
拆分开,前三位 和 后三位依次相加
B
让每个盒子里所剩糖果数为所有盒子糖果数的 min 即可
C
由于数据范围较小,所以暴力
由于 a 只能到 b , z 只能到 y , 所以最少步数就是 两个字母差值的绝对值
void solve()
{
int n, m; cin >> n >> m;
int mi = 0x3f3f3f3f;
vector<string> s(n);
for(int i = 0; i < n; i++) cin >> s[i];
for(int i = 0; i < n - 1; i++) {
for(int j = i + 1; j < n; j++) {
int cnt = 0;
for(int k = 0; k < m; k++) cnt += abs(s[i][k] - s[j][k]);
mi = min(mi, cnt);
}
}
cout << mi << '\n';
}
D
(傻人办法)
在此处通过对角线延申 , 但此处也可以是边框部分
一个一个计算对角线很复杂,想着把所有对角线的和记录下来
- 左对角线下标之和相等
- 右对角线差值相等 (不想求和时出现负下标,可以加上 \(max(n, m)\))
之后再遍历一遍网格,取最大的和即可
求和时记得减去一个自身
void solve()
{
int n, m; cin >> n >> m;
int u = max(n, m);
vector<ll> left(100000), right(100000);
vector<vector<int>> a(n + 1, vector<int>(m + 1));
ll ma = 0;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) cin >> a[i][j];
}
for(int i = 1; i <= n; i++) {
int q = i, w = 1;
while(q <= n && w <= m) right[i - 1 + u] += a[q][w], q++, w++;
}
for(int i = 2; i <= m; i++) {
int q = 1, w = i;
while(q <= n && w <= m) right[1 - i + u] += a[q][w], q++, w++;
}
for(int i = 1; i <= m; i++) {
int q = 1, w = i;
while(q <= n && w >= 1) left[1 + i] += a[q][w], q++, w--;
}
for(int i = 2; i <= n; i++) {
int q = i, w = m;
while(q <= n && w >= 1) left[i + m] += a[q][w], q++, w--;
}
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
ma = max(ma, left[i + j] + right[i - j + u] - a[i][j]);
}
}
cout << ma << '\n';
}
E
思路很简单,因为 大于等于 即可,就往大了选,从后往前,就是最少糖果数
注意数据范围很大,要使用 后缀和,二分
void solve()
{
int n, q; cin >> n >> q;
vector<int> a(n);
vector<ll> suf(n + 1);
ll su = 0;
for(int i = 0; i < n; i++) {cin >> a[i]; su += a[i];}
sort(a.begin(), a.end());
for(int i = n - 1; i >= 0; i--) suf[n - i] = suf[n - (i + 1)] + a[i];
while(q--) {
int u, ed = 0, cnt = 0; cin >> u;
ll sum = 0;
if(u > su) {cout << -1 << '\n'; continue;}
auto q = lower_bound(suf.begin(), suf.end(), u) - suf.begin();
cout << q << '\n';
}
}
F
本质是 求数组中连续子序列的最大长度 , 加了个条件,这个数组中的数必须出现 \(k\) 次以上
连续子序列的最大长度
-
依次遍历数组中的数(去重后)
-
若 \(x - 1\) 存在,则说明 \(x\) 不应该作为起始点,跳过
-
反之,继续判断 \(x + 1\) 是否存在,存在则 \(cnt++\) ,接着继续判断,直到有一个数不存在为止,这一段就结束了
void solve()
{
int n, k, go = 0; cin >> n >> k;
vector<int> a(n);
map<int, int> mp, st;
ll ma = 0, l = 0, r = 0;
for (int i = 0; i < n; i++) {cin >> a[i]; mp[a[i]]++;}
for (auto& [q, w] : mp) {
if (w >= k) st[q] = 1, go = 1;
}
if (go == 0) { cout << -1 << '\n'; return; }
for (auto& [u, q] : st) {
if (st[u - 1]) continue;
int y = u;
ll cnt = 0;
while (st[y]) y++, cnt++;
if(cnt > ma) l = u, r = y - 1, ma = cnt;
}
cout << l << ' ' << r << '\n';
}
G
dfs求有多少个符合条件的点
这个点为 \(W\), 贡献则为 \(-1\); 为 \(B\) , 贡献则为 \(1\)
当此处 \(cnt[x]\) 为 \(0\) 时,则符合条件
void solve()
{
int n, cn = 0; cin >> n;
vector<int> g[5000], cnt(n + 10);
for(int i = 2; i <= n; i++) {
int u; cin >> u;
g[u].push_back(i);
}
string s; cin >> s;
function<void(int)> dfs = [&] (int u) {
cnt[u] = (s[u - 1] == 'W' ? -1 : 1);
for(auto& q : g[u]) {
dfs(q);
cnt[u] += cnt[q];
}
if(cnt[u] == 0) cn++;
};
cn = 0, dfs(1);
cout << cn << '\n';
}
H
交点 : 只有 前面的位置大于后面的位置 才会出现,则是 逆序对
但是, 位置相同,在同一段区间,我们任意安排,就能多出交点。所以在 \(query\) 时,只需要查询小于等于 \(x - 1\) 的数有多少个即可
树状数组求逆序对
ll tr[N];
int lowbit(int x) {return x & (-x);}
void add(int x, ll u) {
for(int i = x; i <= n; i += lowbit(i)) tr[i] += u;
}
ll query(int x) {
ll ans = 0;
while(x) {
ans += tr[x];
x -= lowbit(x);
}
return ans;
}
void solve()
{
cin >> n;
ll cnt = 0;
memset(tr, 0, sizeof tr);
for(int i = 0; i < n; i++) {
ll u; cin >> u;
cnt += i - query(u - 1);
add(u, 1);
}
cout << cnt << '\n';
}

浙公网安备 33010602011771号