Day 3

Day 3

早晨

我和 zyq 很早就去吃早饭了. lyd 和 lzy 在我们两个吃完早饭后还没出来, 我俩就直接去东师了.

上午

神秘模拟赛.

T1

想了一卡车神秘贪心, 其中最接近正解的一个因为少考虑一层嵌套假了.

最后模拟退火赌出来 \(20pts\) .

T2

做 T2 的时候已经只有 \(30mins\) 了, 打了下性质 \(A\) 结果发现有 \(k = 0\) 导致挂飞.

总结

\(20\) 对我来说是一个很特殊的数字吧. 当初 CSP-S2 就是 \(20\) 分爆冷.

\(20\) 是落败, 是新生, 是不甘, 是曙光, 是过往, 是当下.

离落败, 忍不甘, 忆往昔, 亦往兮.

中午

去吃了个牛肉汉堡, 然后就回东师改题了 —— 没回酒店.

下午(改题)

T1

给你一个长度为 \(2n\) 的序列, 你需要对其进行配对, 保证所有对的差不超过 \(A\), 求差不超过 \(B\) 的最大对数.

\(A \ge B\) .

我们考虑排序后从左到右扫描, 可以证明最多有两层嵌套, 所以我们如果说发现当前值的后两位大于当前已经确定的左端点, 就把当前位置和左端点配对, 不加分.

如果说当前节点和下一位能够配对就加分. 否则, 与前面的左端点进行配对 / 选定新的左端点.

复杂度 \(\mathcal{O}(n \log n)\) .

#include <bits/stdc++.h>
using namespace std;

namespace OI {

#define int long long
#define endl "\n"

constexpr int maxn = 1e6+5;

int T, n;
int A, B, p;
int w[maxn];
int a[maxn];
bool vis[maxn];

void main() {
	cin >> T >> n;
	for (int i = 1; i <= 2 * n; i++) {
		cin >> w[i];
	}
	int initT = T;
	while (T--) {
		cin >> p;
		while (p--) {
			int x, v;
			cin >> x >> v;
			w[x] = v;
		}
		memset(vis, 0, sizeof vis);
		for (int i = 1; i <= 2 * n; i++)
			a[i] = w[i];
		sort(a + 1, a + 1 + 2 * n);
		cin >> A >> B;
		int ret = -1;
		int ready = 0;
		for (int i = 1; i <= 2 * n; i += 2)
			if (a[i + 1] - a[i] > A) {
				ret = -1;
				goto end;
			}
		for (int i = 1; i <= 2 * n; i++) {
			if (vis[i])
				continue;
			vis[i] = 1;
			if (a[i + 2] - a[ready] > A)
				ready = 0;
			else if (a[i + 1] && a[i + 1] - a[i] <= B) {
				ret++;
				vis[i + 1] = 1;
			}
			else if (!ready)
				ready = i;
			else
				ready = 0;
		}
		end:
			cout << ret << endl;
	}
}

#undef int
#undef endl

}

int main() {
	freopen("dove.in", "r", stdin);
	freopen("dove.out", "w", stdout);

	cin.tie(0), cout.tie(0);
	ios::sync_with_stdio(0);

	OI::main();

	return 0;
}

此恨绵绵无绝期

T2

给你一个 \(n \times m\) 的区块和若干个障碍物, 求最大的 \(x \times x\) 能够扫描整个区块.

注意到这个有单调性.

然后我们可以进行二分, \(check\) 函数是 \(BFS\) .

我们要找到一个可以放下你的方块的位置开始 \(BFS\) .

使用二维前缀和 + 差分, 复杂度 \(\mathcal{O}(S \log S)\) .

有点像我以前讲过的一道推箱子的题. 忘了是哪个了, CF 上的圆方树 + BFS.

下午(DS)

T3

这时候发现 T3 没有人切, 寻思抢首切.

给你一个带修的括号序列, 你可以在上面向左右移动, 你的步伐会被记录下来, 问你能不能从左到右走出一个合法括号序列.

我们可以用 std::set 去维护每个连续段的位置, 如果:

  1. 奇数 - 必定不可行
  2. ) 开头 / ( 结尾 - 必定不可行
  3. 没有连续段 - 可行
  4. 有两种连续段且 ( 在左 ) 在右 - 可行

这是显然对, 因为如果有两种连续段你可以来回走配平.

然后你就切了.

#include <bits/stdc++.h>
using namespace std;

namespace OI {

#define int long long
#define endl "\n"

constexpr int maxn = 2e5+5;

int n, q;
string str;
set<int> L, R;

void main() {
    cin >> n >> q;
    cin >> str;
    str = ' ' + str;
    for (int i = 1; i < n; i++)
        if (str[i] == str[i + 1])
            if (str[i] == '(')
                L.insert(i);
            else
                R.insert(i);
    while (q--) {
        int x;
        cin >> x;
        if (n & 1) {
            cout << "NO" << endl;
            continue;
        }
        if (str[x] == '(') {
            str[x] = ')';
            if (x > 1)
                if (str[x - 1] == '(')
                    L.erase(x - 1);
                else
                    R.insert(x - 1);
            if (x < n)
                if (L.count(x))
                    L.erase(x);
                else
                    R.insert(x);
        } else {
            str[x] = '(';
            if (x > 1)
                if (str[x - 1] == ')')
                    R.erase(x - 1);
                else
                    L.insert(x - 1);
            if (x < n)
                if (R.count(x))
                    R.erase(x);
                else
                    L.insert(x);
        }
        if (str[1] == ')' || str[n] == '(')
            cout << "NO" << endl;
        else if (L.empty() && R.empty())
            cout << "YES" << endl;
        else if (L.empty() || R.empty())
            cout << "NO" << endl;
        else if ((*L.begin() < *R.begin()) && (*L.rbegin() < *R.rbegin())) 
            cout << "YES" << endl;
        else 
            cout << "NO" << endl;
    }
}


#undef int
#undef endl

}

int main() {
    cin.tie(0), cout.tie(0);
    ios::sync_with_stdio(0);

    OI::main();

    return 0;
}

说实话这题有点史.

CodeForces 忙

首切被抢了.

T1

给你若干次操作, 每次往数组里加入两个数字. 返回数组中位数.

告诉你中位数序列, 问你中位数序列是否可能出现.

很简单啊, 每次把当前的 \(b_i\)\(b_{i - 1}\) 进行判断, 看他们在 \(set\) 里是否相邻就好了.

#include <bits/stdc++.h>
using namespace std;

namespace OI {

#define int long long
#define endl "\n"

constexpr int maxn = 2e5+5;

int T, n;
int b[maxn];
set<int> st;

void main() {
    cin >> T;
    while (T--) {
        cin >> n;
        st.clear();
        bool flag = 0;
        for (int i = 1; i <= n; i++) {
            cin >> b[i];
            if (flag)
                continue;
            st.insert(b[i]);
            if (i > 1) {
                if (b[i] > b[i - 1]) {
                    if (st.upper_bound(b[i - 1]) != st.lower_bound(b[i])) {
                        cout << "NO" << endl;
                        flag = 1;
                    }
                } else if (b[i - 1] > b[i]) {
                    if (st.lower_bound(b[i - 1]) != st.upper_bound(b[i])) {
                        cout << "NO" << endl;
                        flag = 1;
                    }
                }
            }
        }
        if (!flag)
            cout << "YES" << endl;
    }
}

#undef int
#undef endl

}

int main() {
    cin.tie(0), cout.tie(0);
    ios::sync_with_stdio(0);

    OI::main();

    return 0;
}

T2

没写完, 写了个线段树 MLE 了.

晚上

今日无晚自习.

回宾馆之后开始打麻将.

多次尝试做国士无双无果, 和的基本都是小牌.

image

(三家做国, 最后我放弃做过和了)

image

(神秘流局, zyq 听国和红中结果两家一人一对)

诈骗时刻!
(此时我上听了,和西风七小对)
zyq: 我是不是该防守啊, 航空兵不是就喜欢和那些奇奇怪怪的东西么
hkb: 你就打呗, 什么安牌字牌就往外打啊
zyq: 万一你和字牌呢?
hkb: 谁家好人和字牌啊?
lyd: 还真不一定, 偶尔会有人和字牌
zyq: 那你不和字牌啊, 那我打了(西风)
hkb: \(\textcolor{red}{他信了!!!}\)

(无图)

最后一把吃 \(1st\) 了.

晚上回宿舍的时候把脑袋磕到了, 流了点脓血.

事件 —— 水淹七军

由于我和 zyq 生活习惯不同, 我把花洒挂在上面的时候花洒的朝向是浴室外面.

zyq 为了提前预热水温, 在穿着衣服的时候就给花洒打开了, 然后他湿身了.

EEEEEEEE

神秘对话

zyq: 你要不再把花洒冲着外面穿衣服呢?
hkb: 有何不敢!
(我给花洒打开了, 然后衣服右边全湿了)

半夜

ad29b9a5968496db7c7d824a7f860702
fd5186ed15ff93abb9e46266d8dc6d86

后来在和别人下飞行棋, 输完了.

怎么会有人连续两次扔三个六啊!怎么是我!

嗯。最有喜感的一天.

返回目录
posted @ 2026-07-29 11:08  Kibrel  阅读(6)  评论(0)    收藏  举报