C. ~
注意到条件 \(2\),可知峰点在左谷点在右
也就是统计相邻两数之间满足 <<..<>..>><.. 这样的子段个数
考虑如何计算答案:固定中间所有的 >,然后两边的 < 任选,根据乘法原理,将两边的 < 的个数乘起来就是对答案的贡献
这里做一下字符串压缩再统计会比较方便
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
using P = pair<int, int>;
int main() {
int n;
cin >> n;
vector<int> p(n);
rep(i, n) cin >> p[i];
vector<int> d;
rep(i, n-1) d.push_back((p[i] < p[i+1]) ? 0 : 1);
vector<P> rle;
for (int x : d) {
if (rle.size() and rle.back().first == x) rle.back().second++;
else rle.emplace_back(x, 1);
}
ll ans = 0;
rep(i, rle.size()) {
if (rle[i].first == 1) {
ll l = 0, r = 0;
if (0 < i) l = rle[i-1].second;
if (i+1 < rle.size()) r = rle[i+1].second;
ans += l*r;
}
}
cout << ans << '\n';
return 0;
}
D. Garbage Removal
开两个 vector<set<int>> 乱搞
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
int h, w, n;
cin >> h >> w >> n;
vector<set<int>> row(h), col(w);
rep(i, n) {
int x, y;
cin >> x >> y;
--x; --y;
row[x].insert(y);
col[y].insert(x);
}
int q;
cin >> q;
rep(qi, q) {
int type, i;
cin >> type >> i;
--i;
int ans = 0;
if (type == 1) {
ans = row[i].size();
for (int j : row[i]) col[j].erase(i);
row[i] = set<int>();
}
else {
ans = col[i].size();
for (int j : col[i]) row[j].erase(i);
col[i] = set<int>();
}
cout << ans << '\n';
}
return 0;
}
E. Popcount Sum 3
数位dp
记 dp[i][j][s][p] 表示已经确定了高 \(i\) 位,所有位是否和 \(n\) 匹配(匹配:\(s=0\), 不匹配:\(s=1\)),前面是否已经有高位被设置为 \(1\)(是: \(j=1\),否:\(j=0\)),\(\operatorname{popcount}\) 是否为 \(p\)
代码实现
#include <bits/stdc++.h>
#include <atcoder/all>
using namespace atcoder;
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
using mint = modint998244353;
const int M = 60;
mint dp[61][2][2][61];
void solve() {
ll n; int k;
cin >> n >> k;
n++;
rep(i, M+1)rep(j, 2)rep(s, 2)rep(p, k+1) dp[i][j][s][p] = 0;
dp[M][0][0][0] = 1;
for (int i = M-1; i >= 0; --i) {
rep(j, 2)rep(s, 2)rep(p, k+1) {
mint now = dp[i+1][j][s][p];
if (now == 0) continue;
rep(a, 2) {
int ns = s, np = p+a;
if (s == 0) {
if (a < (n>>i&1)) ns = 1;
if (a > (n>>i&1)) continue;
}
if (np > k) continue;
dp[i][j][ns][np] += now;
if (j == 0 and a) dp[i][1][ns][np] += now*(1ll<<i);
}
}
}
mint ans = dp[0][1][1][k];
cout << ans.val() << '\n';
}
int main() {
int t;
cin >> t;
while (t--) solve();
return 0;
}
F. Compare Tree Weights
dfs序+树状数组
代码实现
#include <bits/stdc++.h>
#include <atcoder/all>
using namespace atcoder;
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using P = pair<int, int>;
int main() {
int n;
cin >> n;
vector<vector<int>> to(n);
vector<P> es;
rep(i, n-1) {
int a, b;
cin >> a >> b;
--a; --b;
es.emplace_back(a, b);
to[a].push_back(b);
to[b].push_back(a);
}
vector<int> in(n), out(n); int vid = 0;
auto dfs = [&](auto& f, int v, int p=-1) -> void {
in[v] = vid++;
for (int u : to[v]) {
if (u == p) continue;
f(f, u, v);
}
out[v] = vid;
};
dfs(dfs, 0);
fenwick_tree<int> t(n);
rep(i, n) t.add(i, 1);
int q;
cin >> q;
rep(qi, q) {
int type;
cin >> type;
if (type == 1) {
int v, w;
cin >> v >> w;
--v;
t.add(in[v], w);
}
else {
int ei;
cin >> ei;
--ei;
auto [a, b] = es[ei];
if (in[a] < in[b]) swap(a, b);
int as = t.sum(in[a], out[a]);
int bs = t.sum(0, n) - as;
cout << abs(as-bs) << '\n';
}
}
return 0;
}
G. Travelling Salesman Problem
记 dp[i][x] 表示拿到物品 \(i\) 且位于坐标 \(x\) 的最小代价
然后用 \(\operatorname{slope trick}\) 优化一下即可
浙公网安备 33010602011771号