真的是好久没打(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)斤的孩子