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\)斤的孩子

posted @ 2019-11-14 11:06  MorsLin  阅读(132)  评论(0编辑  收藏  举报