C. 403 Forbidden
对于询问1,可以维护一个set来记录到目前为止出现的所有 (x, y)
二元组
对于询问2,可以开一个状态数组来记录第 \(x\) 个人是否可以访问所有网页
代码
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using P = pair<int, int>;
int main() {
int n, m, q;
cin >> n >> m >> q;
vector<bool> all(n+1);
set<P> privs;
rep(qi, q) {
int type, x;
cin >> type >> x;
if (type == 2) {
all[x] = true;
}
else {
int y;
cin >> y;
if (type == 1) {
privs.emplace(x, y);
}
if (type == 3) {
if (all[x] or privs.count(P(x, y))) puts("Yes");
else puts("No");
}
}
}
return 0;
}
D. Forbidden Difference
序列的排列顺序并不重要,可以按值模 \(D\) 的余数分别考虑
这样一来,例如,如果新建一个表示 \(A\) 中 \(D, 2D, 3D, 4D, \cdots\) 的个数的序列,问题就变成了“当不能同时选择相邻元素时,和的最大值是多少”
这个问题是经典的链的独立集的问题
记 dp[i][0/1]
表示从前 \(i\) 个数中选若干个数且最后一个数选或不选时的最大独立集
还需要特判一下 \(D=0\) 这种情况
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int solve(vector<int> a) {
int n = a.size();
vector dp(n+1, vector<int>(2));
rep(i, n) {
dp[i+1][1] = max(dp[i][0], dp[i][1]);
dp[i+1][0] = dp[i][1]+a[i];
}
int mx = max(dp[n][0], dp[n][1]);
int sum = 0;
rep(i, n) sum += a[i];
return sum-mx;
}
int main() {
int n, d;
cin >> n >> d;
const int M = 1000005;
vector<int> cnt(M);
rep(i, n) {
int a;
cin >> a;
cnt[a]++;
}
int ans = 0;
if (d == 0) {
rep(i, M) {
if (cnt[i] > 0) ans += cnt[i]-1;
}
}
else {
rep(si, d) {
vector<int> a;
for (int i = si; i < M; i += d) {
a.push_back(cnt[i]);
}
ans += solve(a);
}
}
cout << ans << '\n';
return 0;
}
E. Forbidden Prefix
先将所有字符串插到 \(\operatorname{Trie}\) 树上
对于 \(\operatorname{Trie}\) 树上每个点维护它是否存在,对于 \(T_i=1\) 这个操作,暴力地将这个字符串在 \(\operatorname{Trie}\) 树上对应的点 \(v\) 的子树上的所有点删掉(特别地,删过一次的点,以它为根的子树就不用再删了,所以复杂度是正确的),同时将答案减去当前点对应的 \(Y\) 串个数
对于 \(T_i=2\) 这个操作,对答案加 \(1\),并将这个字符串对应的点所在的 \(Y\) 串的个数加 \(1\)
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using P = pair<int, int>;
struct Trie {
using MP = map<char, int>;
vector<MP> to;
Trie(): to(1) {}
int add(const string& s) {
int v = 0;
for (char c : s) {
if (to[v].count(c) == 0) {
int u = to.size();
to[v][c] = u;
to.push_back(MP());
}
v = to[v][c];
}
return v;
}
int ans;
vector<bool> ng;
vector<int> num_y;
void init() {
ans = 0;
int n = to.size();
ng.resize(n);
num_y.resize(n);
}
void addx(int v) {
if (ng[v]) return;
ng[v] = true;
ans -= num_y[v];
for (auto [c, u] : to[v]) addx(u);
}
void addy(int v) {
if (ng[v]) return;
ans++;
num_y[v]++;
}
};
int main() {
int q;
cin >> q;
Trie t;
vector<P> qs;
rep(qi, q) {
int type;
string s;
cin >> type >> s;
int v = t.add(s);
qs.emplace_back(type, v);
}
t.init();
for (auto [type, v] : qs) {
if (type == 1) t.addx(v); else t.addy(v);
cout << t.ans << '\n';
}
return 0;
}
F. Shortest One Formula
dp
只需按值从小到大的顺序,求出长度最小的 expr
、 term
和 factor
即可!
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
int n;
cin >> n;
vector<string> dp_expr(n+1);
vector<string> dp_term(n+1);
vector<string> dp_factor(n+1);
auto chmin = [&](string& s, const string& t) {
if (t == "") return;
if (s == "" or t.size() < s.size()) s = t;
};
for (int i = 1; i <= n; i = i*10+1) dp_factor[i] = to_string(i);
for (int i = 1; i <= n; ++i) {
rep(k, 2) {
chmin(dp_expr[i], dp_term[i]);
for (int j = 1; j < i; ++j) {
if (dp_expr[j] == "") continue;
if (dp_term[i-j] == "") continue;
chmin(dp_expr[i], dp_expr[j]+"+"+dp_term[i-j]);
}
chmin(dp_term[i], dp_factor[i]);
for (int j = 1; j <= i; ++j) {
if (i%j) continue;
if (dp_term[j] == "") continue;
if (dp_factor[i/j] == "") continue;
chmin(dp_term[i], dp_term[j]+"*"+dp_factor[i/j]);
}
if (dp_expr[i] != "") chmin(dp_factor[i], "("+dp_expr[i]+")");
}
}
cout << dp_expr[n] <<'\n';
return 0;
}
G. Odd Position Sum Query
动态开点线段树或平衡树
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
struct S {
int cnt;
ll sum0, sum1;
S(): cnt(0), sum0(0), sum1(0) {}
S(int x): cnt(1), sum0(x), sum1(0) {}
S& operator+=(const S& s) {
if (cnt&1) {
sum0 += s.sum1; sum1 += s.sum0;
}
else {
sum0 += s.sum0; sum1 += s.sum1;
}
cnt += s.cnt;
return *this;
}
S operator+(const S& s) const { return S(*this)+=s; }
};
struct segtree {
int n;
unordered_map<int, S> d;
segtree(int mx=0) {
n = 1;
while (n < mx) n <<= 1;
}
void add(int i, S s) {
i += n;
d[i] += s;
while (i > 1) {
i >>= 1;
int l = i<<1, r = l|1;
d[i] = d[l]+d[r];
}
}
S get() { return d[1]; }
};
int main() {
int q;
cin >> q;
const ll mod = 1e9;
segtree t(mod);
ll z = 0;
rep(qi, q) {
ll y;
cin >> y;
ll x = (y+z)%mod + 1;
t.add(x, S(x));
z = t.get().sum0;
cout << z << '\n';
}
return 0;
}