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

原文地址:https://www.cnblogs.com/morslin/p/11855634.html