说怪话
P6196 [EER1] 代价
将操作倒着想,容易想到在两个 1 的中间加数代价小。
code
const int N = 1e6 + 5;
int n, a[N], cnt;
i64 pre[N], suf[N], ans;
int main() {
read(n); a[0] = a[n + 1] = 1;
rep(i, 1, n) read(a[i]);
for (int l = 0, r = 1; r <= n + 1; l = r, r++) {
while (a[r] != 1) r++;
cnt++;
if (l + 1== r) continue;
i64 res = 2e18;
rep(i, l + 1, r - 1) pre[i] = (i64)a[i] * a[i + 1];
per(i, r - 1, l + 1) suf[i] = (i64)a[i] * a[i - 1];
rep(i, l + 1, r - 1) pre[i] += pre[i - 1];
per(i, r - 1, l + 1) suf[i] += suf[i + 1];
rep(i, l + 1, r - 1) chkmin(res, pre[i - 1] + suf[i + 1] + a[i]);
ans += res;
}
ans += cnt - 1;
write(ans);
return 0;
}
P6381 『MdOI R2』Odyssey
容易想到拓扑排序计算最长路,有 \(\mathcal{O}(\sum\limits_{i = 1}^{n}in(i)\times out(i))\) 的做法。
考虑到问题在于对于边一对一匹配,这很慢。自然能想到进行集合。
对 \(w\) 进行质因数分解,得到 \(w = \sum\limits_{i = 1, p_i\mid w}p_i^{k_i}\)。将 \(w\) 映射为 \(w' = \sum\limits_{i = 1, p_i\mid w}p_i^{k_i \bmod k}\)。这样对于 \(w'\),与其匹配的边是唯一的。
DP 显然。复杂度为 \(\mathcal{O}(n + m)\)。
code
const int N = 1e5 + 5;
int n, m, k, ans;
unordered_map<int, int> f[N];
int tran(int x) {
i64 res = 1;
rep(i, 2, sqrt(x)) if (x % i == 0) {
int c = 0; while (x % i == 0) c++, x /= i;
c %= k; while (c--) res *= i;
}
if (x > 1 && k > 1) res *= x;
return res;
}
int ope(int x) {
i64 res = 1;
rep(i, 2, sqrt(x)) if (x % i == 0) {
int c = 0;
while (x % i == 0) c++, x /= i;
c %= k;
if (c) {
c = k - c;
while (c--) {
res *= i;
if (res > 1e5) return -1;
}
}
}
if (x > 1 && k > 1) {
rep(i, 1, k - 1) {
res *= x;
if (res > 1e5) return -1;
}
}
return res;
}
struct Graph {
int head[N], ver[N << 1], edge[N << 1], wgt[N << 1], Next[N << 1], tot = 1, ind[N], pw[N << 1];
void add(int u, int v, int w, int l) {
Next[++tot] = head[u]; ind[v]++;
ver[head[u] = tot] = v, edge[tot] = l, wgt[tot] = tran(w), pw[tot] = ope(w);
}
} DAG;
void topo() {
queue<int> que;
rep(i, 1, n) if (!DAG.ind[i]) que.push(i);
while (que.size()) {
int u = que.front(); que.pop();
for (int i = DAG.head[u]; i; i = DAG.Next[i]) {
int v = DAG.ver[i], w = DAG.wgt[i], iw = DAG.pw[i], l = DAG.edge[i];
chkmax(f[v][w], f[u][iw] + l);
chkmax(ans, f[v][w]);
if (!(--DAG.ind[v])) que.push(v);
}
}
}
int main() {
read(n, m, k);
rep(i, 1, m) {
int u, v, w, l;
read(u, v, w, l);
DAG.add(u, v, w, l);
}
topo();
write(ans, '\n');
return 0;
}
时间复杂度算错,原因是对时间复杂度模糊的地方没有细想
补题时输入格式写错,虚空调试30min,牛大了
P10675 【MX-S1-T4】先见之明
找到满足 \(\sum\limits_{i = j}^m 2^{p_i} > \sum\limits_{a_x \le p_j} 2^{a_x}\) 的最小的 \(j\),令 \(\min\limits_{a_i > p_j}\{a_i\} = a_u\),答案为 \(\sum\limits_{i = 1}^j2^{p_i} + 2^{a_u}\)。
考虑如何求该位置。
定义 \(g(i)\) 表示 \(\sum\limits_{a_x \le i} 2^{a_x}\) 的最高位,\(h(i) = \sum\limits_{j = i}^m 2^{p_j}\), \(g(i) > i\) 时 \(i\) 显然不是所求,\(g(i) < i\) 时显然是。
讨论 \(g(i) = i\) 的情况。定义 \(f(i)=[\sum\limits_{a_x \le p_j} 2^{a_x} < h(i)]\)。注意到此时相当与两个后缀字符串进行比较。
如果有 \(a_x \in(p_{i - 1}, p_i)\),\(f(i) = 1\),否则,答案取决于 \(f(i + 1)\)。
点击查看代码
const int N = 1e6 + 30;
const int mod = 998244353;
int n, q, s[N], c[N], mp[N], v = N - 10, ps[N], pc[N];
bool f[N];
int pw[N];
void solve() {
int m; read(m); vector<int> p(m + 1);
rep(i, 1, m) read(p[i]); f[m + 1] = 1;
int bk = m + 1, ans = 0;
per(i, m, 1) {
if (i < m && ps[p[i + 1] + 1] < p[i]) f[i + 1] = 1;
f[i] = s[p[i]] ? f[i + 1] : 0;
if (!f[i] && mp[p[i]] <= p[i]) bk = i;
}
rep(i, 1, bk - 1) ans = (ans + pw[p[i]]) % mod;
if (bk <= m) ans = pc[p[bk] + 1] == -1 ? -1 : (ans + pw[pc[p[bk] + 1]]) % mod;
write(ans, '\n');
}
int main() {
pw[0] = 1;
rep(i, 1, v) pw[i] = 2 * pw[i - 1] % mod;
read(n, q);
rep(i, 1, n) {
int x; read(x);
c[x]++;
}
int mx = -1;
rep(i, 0, v) {
s[i] += c[i];
int j = i;
while (s[j] > 1) {
s[j + 1] += s[j] / 2;
s[j] &= 1; j++;
chkmax(mx, j);
}
mp[i] = mx;
}
ps[v] = pc[v] = -1;
per(i, v - 1, 0) {
ps[i] = s[i] ? i : ps[i + 1];
pc[i] = c[i] ? i : pc[i + 1];
}
while (q--) solve();
return 0;
}
浙公网安备 33010602011771号