Codeforces Global Round 1 (CF1110) (未完结,只有 A-F)

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\n", ans);
}

C. Meaningless Operations

好一道打表题。

想得百无聊赖之下开始打表,然后就有惊喜了。

发现除了 \(2^k-1\) 外的数,答案都是比他大的最小的 \(2^k-1\)

那么 \(2^k-1\) 自己呢?一开始没有把表打全,以为就是如果 \(k\) 是偶数,就是 \(a/3\) ,否则就是 \(1\) ,结果交上去 wa2.

于是继续打 \(2^k-1\),其实这个时候可以直接把所有的表直接复制上去。可我偏要找出规律来。好像答案都是原数的因数,而且——而且似乎还是最大的因数啊。

于是就可以 A 掉了。

\[ f(a) = \max_{0 < b < a}{gcd(a \oplus b, a \> \& \> b)}. \]

仔细想一下,对于这个式子,如果 \(a \neq 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\n", s);
        else printf("%d\n", 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\) 个。

那么有

\[ dp[i][j][k] = \max_{l = 0} ^ 2 {dp[i][l][j] + k + \lfloor \frac{num[i] - j - k - l}3 \rfloor} \]

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\n", dp[m][0][0]);
}

E. Magic Stones

一开始捣鼓了半天推出了一堆奇怪的没有用的性质。于是后来干脆直接划掉重新换个思路思考。

记得好像对于序列上进行变化的题目好多都是用差分来做的,所以我开始从差分上考虑。

然后发现好像差分完就没了。

\[ c_i' = c_{i + 1} + c_{i - 1} - c_i\\ \text{可以推得}\\ c_{i + 1} - c_i' = c_i - c_{i - 1}\\ c_i' - c_{i - 1} = c_{i + 1} - c_i \]

也就是说一次操作其实是把差分数组上两个数交换一下。

注意要特判一下两端的原数据,因为两端不可以进行操作。一开始没有注意,就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\n", 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\n", ans[i]);
}

猜你喜欢

转载自www.cnblogs.com/hankeke/p/CF1110.html