• 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
    ", 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 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) 个。

    那么有

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

    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

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

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

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

    [c_i' = c_{i + 1} + c_{i - 1} - c_i\ ext{可以推得}\ 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
    ", 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]);
    }
    
    
  • 相关阅读:
    mysql用户密码修改
    Java List java.lang.UnsupportedOperationException
    python __dict__
    pytest.fixture
    Python __metaclass__ 解释
    Python __new__()方法,为对象分配内存 返回对象的引用
    git 常用操作
    boto3 dynamodb 一些简单操作
    conda, pip, virtualenv 区别
    list去重后不改变排序
  • 原文地址:https://www.cnblogs.com/hankeke/p/CF1110.html
Copyright © 2020-2023  润新知