Codeforces Global Round 1 (CF1110)
继续补题。因为看见同学打了这场,而且涨分还不错,所以觉得这套题目可能会比较有意思。
因为下午要开学了,所以恐怕暂时不能把这套题目补完了,所以先把 A-F 放上来。
A. Parity
保存 %2
的值就可以了。
const int N = 1e5 + 7;
int b, k, a[N], ans;
int main() {
read(b), read(k);
for (int i = 1; i <= k; ++i) read(a[i]);
for (int i = k, p = 1; i; --i, p = p * b % 2) (ans += a[i] * p) %= 2;
if (ans) puts("odd"); else puts("even");
}
B. Tape
一开始准备二分,然后发现他要的是最小的总长度,不太好二分。然后发现我们在断的时候,应该尽量把间隙比较大的优先断掉,所以直接贪心,排个序就可以了。
const int N = 1e5 + 7;
int n, m, k, a[N], b[N], c[N], ans;
int main(){
read(n), read(m), read(k);
for (int i = 1; i <= n; ++i) read(a[i]), b[i - 1] = a[i] - a[i - 1], c[i] = i;
std::sort(c + 1, c + n, [](const int &x, const int &y){return b[x] > b[y];});
std::sort(c + 1, c + k); c[k] = n;
for (int i = 1; i <= k; ++i) ans += a[c[i]] - a[c[i - 1] + 1] + 1;
printf("%d
", ans);
}
C. Meaningless Operations
好一道打表题。
想得百无聊赖之下开始打表,然后就有惊喜了。
发现除了 (2^k-1) 外的数,答案都是比他大的最小的 (2^k-1) 。
那么 (2^k-1) 自己呢?一开始没有把表打全,以为就是如果 (k) 是偶数,就是 (a/3) ,否则就是 (1) ,结果交上去 wa2.
于是继续打 (2^k-1),其实这个时候可以直接把所有的表直接复制上去。可我偏要找出规律来。好像答案都是原数的因数,而且——而且似乎还是最大的因数啊。
于是就可以 A 掉了。
仔细想一下,对于这个式子,如果 (a eq 2^k-1) ,那么 (a) 就不是所有位都为 (1) ,那么令 (b = ~a) ,那么 (a oplus b = 2 ^ k - 1, a > & > b = 0) 。于是 (gcd) 就是 (2^k-1)。
否则呢,如果 (a) 的二进制位全是 (1) ,那么这里的 (b) 应该是 (0) ,显然不满足要求。发现当 (a) 二进制位都是 (1) 时, (a oplus b = a - b), (a > & > b = b) 。于是原式可化为 (f(a) = max limits_{0 < b < a}{gcd(a - b, b)} = max limits_{0 < b < a}{gcd(a, b)}) 。显然当 (b | a) 时 (f(a)) 最大,于是 (b) 就是 (a) 最大的因数。
int q, x;
inline int Get(int x) {
int ans = 0;
while (x) ++ans, x >>= 1;
return ans;
}
inline int Get2(int x) {
if (x == 1) return 0;
for (int i = 2, p = sqrt(x); i <= p; ++i)
if(x % i == 0) return x / i;
return 1;
}
int main() {
read(q);
for (int i = 1; i <= q; ++i) {
read(x); int p = Get(x), s = (1 << p) - 1;
if (s != x) printf("%d
", s);
else printf("%d
", Get2(s));
}
}
D. Jongmah
我感觉这道题比 E,F 都难。可能是因为太菜了才会这样想。(因为目前这六道题里面只有这道题是看题解做的。。。)
首先最重要的结论是 ((i, i + 1, i + 2)) 这样的顺子最多取两个,否则可以自己先把对子 ((i , i, i))取完是不会比原方案差的。
于是我们限制一下顺子取的个数就可以了。
设 (dp[i][j][k]) 表示 dp 到第 (i) 个数,保证对子 ((i - 1, i, i + 1)) 取 (j) 个,对子 ((i, i + 1, i + 2)) 取 (k) 个。
那么有
const int N = 1e6 + 7;
int n, m, x, a[N], dp[N][3][3];
int main() {
#ifdef hzhkk
freopen("hkk.in", "r", stdin);
#endif
read(n); read(m);
for (int i = 1; i <= n; ++i) read(x), ++a[x];
for (int i = 1; i <= m; ++i)
for (int j = 0; j <= 2; ++j)
for (int k = 0; k <= 2; ++k)
for (int l = 0; l <= 2; ++l)
if(a[i] >= j + k + l) SMAX(dp[i][j][k], dp[i - 1][l][j] + k + (a[i] - j - k - l) / 3);
printf("%d
", dp[m][0][0]);
}
E. Magic Stones
一开始捣鼓了半天推出了一堆奇怪的没有用的性质。于是后来干脆直接划掉重新换个思路思考。
记得好像对于序列上进行变化的题目好多都是用差分来做的,所以我开始从差分上考虑。
然后发现好像差分完就没了。
也就是说一次操作其实是把差分数组上两个数交换一下。
注意要特判一下两端的原数据,因为两端不可以进行操作。一开始没有注意,就wa4了一次。
const int N = 1e5 + 7;
int n, m, c[N], t[N];
int main() {
#ifdef hzhkk
freopen("hkk.in", "r", stdin);
#endif
read(n);
for (int i = 1; i <= n; ++i) read(c[i]);
for (int i = 1; i <= n; ++i) read(t[i]);
if (c[1] != t[1] || c[n] != t[n]) return puts("No");
for (int i = n; i > 1; --i) c[i] = c[i] - c[i - 1];
for (int i = n; i > 1; --i) t[i] = t[i] - t[i - 1];
std::sort(c + 2, c + n + 1);
std::sort(t + 2, t + n + 1);
if (!memcmp(c + 2, t + 2, sizeof(int) * (n - 1))) puts("Yes");
else puts("No");
}
F. Nearest Leaf
映象中这道题好像是我们学校学长暑假讲过的原题,但是记不起来了,去翻 ppt 却很神奇地没有找到。
但是不影响这道题确实不难。
显然是离线,把询问挂在 (v) 上,假设 (dis[i]) 表示 (v) 到 (i) 的距离,可以发现,从父亲跳到儿子,会把儿子的子树内的点的 (dis) 值加上 (w) ( (w) 是边权),其余的点减上 (w) 。
直接线段树维护即可。
注意代码里面的 (dis) 数组和上面的分析里面的 (dis) 不是一个东西。
using std::min;
#define lc o << 1
#define rc o << 1 | 1
const int N = 5e5 + 7;
const ll INF = 0x3f3f3f3f3f3f3f3f;
int n, m, x, y, z, dfc, fa[N], dfn[N], num[N], w[N];
ll dis[N], ans[N];
struct Edge {int to, ne, w;} g[N << 1]; int head[N], tot;
inline void Addedge(int x, int y, int z) {g[++tot].to = y; g[tot].w = z; g[tot].ne = head[x]; head[x] = tot;}
struct Question{int l, r; ll *ans;};
std::vector<Question> q[N];
struct Node{ll val, add;} t[N << 2];
inline void Build(int o, int L, int R) {
if (L == R) return (void)(t[o].val = dis[L]);
int M = L + R >> 1;
Build(lc, L, M); Build(rc, M + 1, R);
t[o].val = min(t[lc].val, t[rc].val);
}
inline void Add(int o, int L, int R, int l, int r, ll k) {
// dbg("o = %d, L = %d, R = %d, l = %d, r = %d, k = %d
", o, L, R, l, r, k);
if (l <= L && R <= r) return (void)(t[o].add += k, t[o].val += k);
int M = L + R >> 1;
if (l <= M) Add(lc, L, M, l, r, k);
if (r > M) Add(rc, M + 1, R, l, r, k);
t[o].val = min(t[lc].val, t[rc].val) + t[o].add;
}
inline ll Qmin(int o, int L, int R, int l, int r) {
if (l <= L && R <= r) return t[o].val;
int M = L + R >> 1;
if (r <= M) return Qmin(lc, L, M, l, r) + t[o].add;
if (l > M) return Qmin(rc, M + 1, R, l, r) + t[o].add;
return min(Qmin(lc, L, M, l, r), Qmin(rc, M + 1, R, l, r)) + t[o].add;
}
inline void dfs_pre(int x) {
num[x] = 1;
for fec(i, x, y) dfs_pre(y), num[x] += num[y];
}
inline void dfs(int x) {
if(x > 1) {
Add(1, 1, n, 1, n, w[x]);
Add(1, 1, n, x, x + num[x] - 1, -w[x] << 1);
}
for (auto i : q[x]) *i.ans = Qmin(1, 1, n, i.l, i.r);
for fec(i, x, y) dfs(y);
if(x > 1) {
Add(1, 1, n, 1, n, -w[x]);
Add(1, 1, n, x, x + num[x] - 1, w[x] << 1);
}
}
int main() {
#ifdef hzhkk
freopen("hkk.in", "r", stdin);
#endif
read(n), read(m);
for (int i = 2; i <= n; ++i) read(y), read(z), dis[i] = dis[y] + z, Addedge(fa[i] = y, i, w[i] = z);
for (int i = 2; i <= n; ++i) dis[fa[i]] = INF;
for (int i = 1; i <= m; ++i) read(x), read(y), read(z), q[x].pb((Question){y, z, ans + i});
Build(1, 1, n); dfs_pre(1); dfs(1);
for (int i = 1; i <= m; ++i) printf("%I64d
", ans[i]);
}