zoukankan      html  css  js  c++  java
  • Codeforces Round 576 (Div. 2)

    比赛传送门

    真的是好久没打(CF)了,不过这次做出来四道题(一共六道),虽然第三题(FST)了,不过还是涨了好多(rating)
    之前有两次发挥不佳,掉到了(1286)分,这次直接涨了(143)分,重回青名

    --

    A.City Day

    日常送分题,模拟就好了

    B.Water Lily

    初中数学题,用勾股定理列方程就能解出公式

    C.MP3

    稍微翻译下
    (n)个数
    定义一种操作:指定两个数(l,r ; (l < r)),将所有(<l)的数变为(l),所有(>r)的数变为(r)
    只进行一次这种操作,使数的种类小于(k)种且此操作更改的数尽量少((k = 2 ^ {(I/n)}))

    输入(n,I)和这(n)个数
    输出最少要更改多少个数字

    题解

    先离散化,然后记录下每种数的数量,接下来问题就变成了求长度(<=k)的最大子区间,可以用尺取法,不过我比较懒,因为数都是正数,直接用的前缀和枚举

    要特别注意:(k)可能会非常大,甚至爆(LL),但数最多只有(400000)种,所以(k)其实最大设为(400000)就好了(我就是因为这个(FST)了)。

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #define LL long long
    using namespace std;
    LL read() {
        LL k = 0, f = 1; char c = getchar();
        while(c < '0' || c > '9') {
            if(c == '-') f = -1;
            c = getchar();
        }
        while(c >= '0' && c <= '9')
            k = k * 10 + c - 48, c = getchar();
        return k * f;
    }
    int a[400010], b[400010];
    int tong[400010], sum[400010];
    int main() {
        int n = read(), I = read() * 8;
        for(int i = 1; i <= n; ++i) a[i] = b[i] = read();
        int k;
        if(I/n < 31) 
           k = 1 << (I/n);
        else k = 5000010;
        sort(b+1, b+n+1); int pos = unique(b+1, b+n+1) - b - 1;
        for(int i = 1; i <= n; ++i) {
            a[i] = lower_bound(b+1, b+pos+1, a[i]) - b;
            ++tong[a[i]];
        }
        for(int i = 1; i <= pos; ++i) sum[i] = sum[i-1] + tong[i];
        int minn = 2147483647;
        for(int i = 1; i <= pos; ++i) {
            int pre = max(0, i - k);
            if(n - (sum[i] - sum[pre]) < minn)
                minn = n - (sum[i] - sum[pre]);
        }
        cout << minn << endl;
        return 0;
    }
    

    D.Welfare State

    第四题是我比较擅长的数据结构题,所以比较幸运的把它(A)

    翻译

    (n)个数,(q)个操作
    操作有两种:
    1 p x:将(p)位置上的数变为(x)
    2 x:将所有小于(x)的数变为(x)

    输出经过(q)次操作后的这(n)个数

    题解

    不知道官方正解是什么,不过我用的线段树

    用线段树维护区间最小值,对于操作(2),直接修改([1,n])的最小值并打上懒标记,对于操作(1),就直接单点修改并一路下传懒标记就可以了
    输出就每个点单点询问+下传懒标记

    算是比较基础的线段树题吧

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define LL long long
    #define ls p << 1
    #define rs p << 1 | 1
    #define mid ((l + r) >> 1)
    using namespace std;
    LL read() {
    	LL k = 0, f = 1; char c = getchar();
    	while(c < '0' || c > '9') {
    		if(c == '-') f = -1;
    		c = getchar();
    	}
    	while(c >= '0' && c <= '9')
    		k = k * 10 + c - 48, c = getchar();
    	return k * f;
    }
    int tree[200010 << 2], tag[200010 << 2], a[200010];
    inline void up(int p) {
    	tree[p] = min(tree[ls], tree[rs]);
    }
    void build(int l, int r, int p) {
    	if(l == r) {
    		tree[p] = a[l]; return ;
    	}
    	build(l, mid, ls); build(mid+1, r, rs);
    	up(p);
    }
    inline void down(int l, int r, int p) {
    	tag[ls] = max(tag[ls], tag[p]);
        tag[rs] = max(tag[rs], tag[p]);
    	tree[ls] = max(tree[ls], tag[p]);
    	tree[rs] = max(tree[rs], tag[p]);
    	tag[p] = 0;
    }
    void update1(int pos, int l, int r, int p, int k) {
        if(l == r) {
            tree[p] = k; return ;
        }
        down(l, r, p);
        if(pos <= mid) update1(pos, l, mid, ls, k);
        else update1(pos, mid+1, r, rs, k);
        up(p);
    }
    void update2(int nl, int nr, int l, int r, int p, int k) { //别问我为什么要写一个函数,我是智障
    	if(l >= nl && r <= nr) {
    		tree[p] = max(tree[p], k); tag[p] = max(tag[p], k);
    		return ;
    	}
    	down(l, r, p);
    	if(nl <= mid) update2(nl, nr, l, mid, ls, k);
    	if(nr > mid) update2(nl, nr, mid+1, r, rs, k);
    	up(p);
    }
    int query(int pos, int l, int r, int p) {
        if(l == r) {
            return tree[p];
        }
        down(l, r, p);
        if(pos <= mid) return query(pos, l, mid, ls);
        else return query(pos, mid+1, r, rs);
        up(p);
    }
    int main() {
    	int n = read();
        memset(tree, 127, sizeof(tree));
    	for(int i = 1; i <= n; ++i) a[i] = read();
    	build(1, n, 1);
        int m = read();
    	while(m--) {
    		int opt = read(), x = read();
    		if(opt == 1) {
    			int k = read();
    			update1(x, 1, n, 1, k);
    		}
    		else update2(1, n, 1, n, 1, x);
    	}
    	for(int i = 1; i <= n; ++i)
            printf("%d ", query(i, 1, n, 1));
    	return 0;
    }
    

    后记

    作完这四道题就去睡觉了,躺在床上还担心会不会(FST),后来果然一语成谶,不过还好是(C)题而不是(D)
    醒来一看涨了(143)分,开心的像一个(160)斤的孩子

  • 相关阅读:
    《算法笔记》9. 培养贪心思维、贪心算法深度实践
    《算法笔记》8. 二叉树的递归思维实战
    《算法笔记》7. 二叉树基本算法整理
    《算法笔记》6. 链表相关面试题总结
    大家是怎么做APP接口的版本控制的?欢迎进来看看我的方案。升级版的Versioning
    secure 审计暴力登陆
    linux 查询登陆成功、失败的用户
    win10 ctrl与alt键互换
    如何保证外包团队接入企业内网安全
    学习正则匹配的一些经验
  • 原文地址:https://www.cnblogs.com/morslin/p/11855634.html
Copyright © 2011-2022 走看看