首页 > 其他分享 >[赛记] NOIP2024加赛1 && 多校A层冲刺NOIP2024模拟赛18

[赛记] NOIP2024加赛1 && 多校A层冲刺NOIP2024模拟赛18

时间:2024-11-08 09:58:57浏览次数:6  
标签:rt 赛记 int siz tt tr long 加赛 NOIP2024

暴力错解大赛

玩游戏 82pts

乱糊的错解,正确性和时间复杂度都不对,但是拿了82pts;

对于正解,考虑从 $ k $ 将原序列分成两个部分,左边和右边,然后分别求一次前缀和(注意这里,可以省去很多分讨和常数),设前一个前缀和数组为 $ a $,后一个为 $ b $,那么问题就转化成有两个指针 $ i, j $,可以任意移动,询问是否可以将其都移到数组最后,但在每一个时刻都要满足 $ a_i + b_j \leq 0 $;

那么贪心的思路是每次看看能不能将 $ i $ 或 $ j $ 移动到下一个比它小的位置,如果能就移过去,正确性挺对;

但是这样只能将这两个指针移动到数组中最小的位置,考虑到后面的移动其实就是前面的移动的反方向,所以将数组倒过来再做一遍即可,时间复杂度 $ \Theta(Tn) $,常数有些大;

注意实现时有很多细节,要小心处理,注意边界,要不然一不小心时间复杂度就炸了;

注意为了保证时间复杂度,在实现过程中要时刻保证 $ i, j $ 单调,具体的,可以开一个 $ pos $ 数组存储现在这一位到的位置,然后下次遍历时直接从这里遍历即可;

点击查看代码
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int t;
int n, k;
long long a[500005], b[500005], c[500005], bmi, cmi;
int blen, clen, bpos, cpos;
int pos[2][500005];
bool ans;
void w() {
	int l = 0, r = 0;
	long long sum = 0;
	while(1) {
		if (l == bpos && r == cpos) break;
		long long now = 0;
		bool vis = false;
		if (l != bpos) {
			for (int i = pos[0][l]; i <= blen; i++) {
				now = sum - b[l] + b[i];
				if (now > 0) {
					pos[0][l] = i;
					break;
				}
				if (now <= sum) {
					l = i;
					sum = now;
					vis = true;
					break;
				}
				if (i == blen) pos[0][l] = blen;
			}
		}
		if (r != cpos) {
			for (int i = pos[1][r]; i <= clen; i++) {
				now = sum - c[r] + c[i];
				if (now > 0) {
					pos[1][r] = i;
					break;
				}
				if (now <= sum) {
					r = i;
					sum = now;
					vis = true;
					break;
				}
				if (i == clen) pos[1][r] = clen;
			}
		}
		if (!vis) {
			if (r == 0) {
				r = 1;
				sum = b[l] + c[r];
				if (sum > 0) {
					ans = false;
					break;
				}
			} else if (l == 0) {
				l = 1;
				sum = b[l] + c[r];
				if (sum > 0) {
					ans = false;
					break;
				}
			} else {
				ans = false;
				break;
			}
		}
	}
}
int main() {
	// freopen("in.in", "r", stdin);
	// freopen("out.out", "w", stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> t;
	while(t--) {
		cin >> n >> k;
		for (int i = 1; i <= n; i++) {
			cin >> a[i];
		}
		bmi = 2e18;
		cmi = 2e18;
		cpos = bpos = 0;
		for (int i = k; i >= 2; i--) {
			blen++;
			b[blen] = b[blen - 1] + a[i];
			if (bmi >= b[blen]) {
				bmi = b[blen];
				bpos = blen;
			}
		}
		b[blen + 1] = 2e18;
		for (int i = k + 1; i <= n; i++) {
			clen++;
			c[clen] = c[clen - 1] + a[i];
			if (cmi >= c[clen]) {
				cmi = c[clen];
				cpos = clen;
			}
		}
		c[clen + 1] = 2e18;
		for (int i = 0; i <= blen; i++) pos[0][i] = i + 1;
		for (int i = 0; i <= clen; i++) pos[1][i] = i + 1;
		ans = true;
		w();
		reverse(b + 1, b + 1 + blen);
		reverse(c + 1, c + 1 + clen);
		if (bpos != 0) bpos = blen - bpos + 1;
		if (cpos != 0) cpos = clen - cpos + 1;
		for (int i = 0; i <= blen; i++) pos[0][i] = i + 1;
		for (int i = 0; i <= clen; i++) pos[1][i] = i + 1;
		w();
		if (c[1] == 2e18) c[1] = 0;
		if (b[1] == 2e18) b[1] = 0;
		if (c[1] + b[1] > 0) ans = false;
		if (ans) cout << "Yes" << '\n';
		else cout << "No" << '\n';
		for (int i = 1; i <= blen + 1; i++) b[i] = 0;
		for (int i = 1; i <= clen + 1; i++) c[i] = 0;
		for (int i = 0; i <= blen; i++) pos[0][i] = 0;
		for (int i = 0; i <= clen; i++) pos[1][i] = 0;
		blen = 0;
		clen = 0;
	}
	return 0;
}

矩形 20pts

不喷了,题解错了,std和题解写的根本不是一个东西

然后我没发现,就按照题解打了三个树套树,然后就没然后了;

其实好像上个扫描线就行,没写,被题解恶心到了

想看正解请自行翻阅其它博客;

选彩笔(rgb)60pts

赛时树套树求解三维数点 + 二分答案假了,60pts;

其实正解就是三维数点,先二分一个答案 $ mid $,考虑一个 $ mid \times mid \times mid $ 的立方体,只要我们在这个由值域 $ V $ 所组成的三维空间 $ V \times V \times V $ 中找到这样一个立方体,满足其内部的点数 $ \geq k $ 即可;

那么可以 三维前缀和 + 容斥 处理,时间复杂度:$ \Theta(V^3 \log V) $;

注意原题中有 $ 0 $,所以要将输入的三个参数都 $ + 1 $;

经验:一般想到树套树的题都不用树套树做(可能能拿部分分或者错解骗分);

点击查看代码
#include <iostream>
#include <cstdio>
using namespace std;
int n, kk;
int sum[266][266][266];
bool ck(int x) {
	int su = 0;
	for (int i = 1; i + x <= 256; i++) {
		for (int j = 1; j + x <= 256; j++) {
			for (int k = 1; k + x <= 256; k++) {
				su = sum[i + x][j + x][k + x] - sum[i - 1][j + x][k + x] - sum[i + x][j - 1][k + x] - sum[i + x][j + x][k - 1] + sum[i - 1][j - 1][k + x] + sum[i - 1][j + x][k - 1] + sum[i + x][j - 1][k - 1] - sum[i - 1][j - 1][k - 1];
				if (su >= kk) return true;
			}
		}
	}
	return false;
}
int main() {
	freopen("rgb.in", "r", stdin);
	freopen("rgb.out", "w", stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n >> kk;
	int x, y, z;
	for (int i = 1; i <= n; i++) {
		cin >> x >> y >> z;
		sum[++x][++y][++z]++;
	}
	for (int i = 1; i <= 256; i++) {
		for (int j = 1; j <= 256; j++) {
			for (int k = 1; k <= 256; k++) {
				sum[i][j][k] += sum[i - 1][j][k] + sum[i][j - 1][k] + sum[i][j][k - 1] - sum[i - 1][j - 1][k] - sum[i - 1][j][k - 1] - sum[i][j - 1][k - 1] + sum[i - 1][j - 1][k - 1];
			}
		}
	}
	int l = 0;
	int r = 225;
	int ans = 0;
	while(l <= r) {
		int mid = (l + r) >> 1;
		if (ck(mid)) {
			ans = mid;
			r = mid - 1;
		} else l = mid + 1;
	}
	cout << ans;
	return 0;
}

兵蚁排序(sort)100pts

按照样例二模拟即可;

因为操作数 $ \leq n^2 $ 所以我们尽量让操作数等于 $ n^2 $;

每次将大的一步一步向前交换过来就行;

正确性:因为这样会尽可能的保留 $ a $ 原来的结构以便下一次操作,贪心的想一想是对的;

时间复杂度:$ \Theta(Tn^2) $;

点击查看代码
#include <iostream>
#include <cstdio>
using namespace std;
int t;
int n;
int a[500005], b[500005];
pair<int, int> an[500005];
int cnt;
int main() {
	freopen("sort.in", "r", stdin);
	freopen("sort.out", "w", stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> t;
	while(t--) {
		cin >> n;
		cnt = 0;
		for (int i = 1; i <= n; i++) {
			cin >> a[i];
		}
		for (int i = 1; i <= n; i++) {
			cin >> b[i];
		}
		bool ans = true;
		for (int i = 1; i <= n; i++) {
			if (a[i] == b[i]) continue;
			int mi = 0x3f3f3f3f;
			int pos = 0;
			for (int j = i; j <= n; j++) {
				mi = min(mi, a[j]);
				if (a[j] == b[i]) {
					pos = j;
					break;
				}
			}
			if (mi < b[i] || !pos) {
				ans = false;
				break;
			}
			for (int j = pos - 1; j >= i; j--) {
				an[++cnt] = {j, j + 1};
				swap(a[j], a[j + 1]);
			}
		}
		if (!ans) {
			cout << -1 << '\n';
		} else {
			cout << 0 << '\n';
			cout << cnt << '\n';
			for (int i = 1; i <= cnt; i++) {
				cout << an[i].first << ' ' << an[i].second << '\n';
			}
		}
	}
	return 0;
}

银行的源起(banking)10pts

按照题意模拟10pts;

考虑正解,首先考虑只有一个银行怎么做;

那么对于这种题,我们有一种套路,就是考虑每条边的贡献

首先钦定 $ 1 $ 为根;

那么考虑走这条边的人数,发现银行只可能在子树里或者在子树外,所以一条边 $ (x, u) $ (其中 $ u $ 为儿子)的贡献为 $ w \times \min(siz_u, siz_1 - siz_u) $;

考虑为什么是对的,因为在这棵树上,会有一个节点满足其儿子的 $ siz < siz_1 - siz_u $ ,但是其自身的 $ siz \geq siz_1 - siz $,这个节点就可以是银行,并且它上面的点都满足 $ siz > siz_1 - siz $,所以是对的;

这个问题直接 $ \Theta(n) $ 就做完了;

考虑两个银行的情况,我们不难发现,原图中会有一条边没人走,因为这两个节点的最近的银行不一样,且只会有一条边,因为只有两个银行,原图只能被分成两个连通块;

那么我们可以枚举这一条边,然后对这两个连通块分别做一次 $ \Theta(n) $ 的做法,就得到了 $ \Theta(n^2) $ 的做法;

考虑如何优化;

对式子 $ w \times \min(siz_u, siz_1 - siz_u) $ 下手,此时对于这条边 $ (x, u) $,我们钦定把它断开,于是原图分成两部分,我们以 $ u $ 子树为例,拆开这个式子:

设 $ X = siz_u $;

原式可以化为(其中 $ y $ 是 $ u $ 的后代):

\[w \times siz_y [siz_y \leq \frac{X}{2}] + w \times X [siz_y > \frac{X}{2}] - w \times siz_y [siz_y > \frac{X}{2}] \]

那么对于一条边 $ (x, u) $,其中 $ u $ 为儿子,我们将 $ u $ 和这条边 $ (x, u) $ 看作一体,这样的话我们直接开两棵以 $ siz $ 为下标的动态开点线段树,一棵记录 $ \sum w $,一棵记录 $ \sum w \times siz $ 就解决了这个问题;

对于 $ u $ 子树外的点同理,但是要特殊判断 $ 1 $ 到 $ u $ (不包含 $ u $)的这条链的情况,因为它们的 $ siz $ 不同;

这样的话,我们在全局开两棵线段树记录所有的 $ \sum w $ 和 $ \sum w \times siz $ (一棵也行),然后对于链再开两棵线段树记录一下这个链的情况,注意在递归向下的时候对全局的线段树进行删除操作,回溯的时候进行加操作,对于链正好反过来;

因为我们要查询某一个子树,所以对子树在开两棵线段树,并且回溯的时候进行合并即可;

这样我们开了六棵线段树就解决了这个问题;

时间复杂度:$ \Theta(n \log V) $,其中 $ V $ 是 $ \max siz $,常数极大,只能拿82pts(具体见[PEP] 关于卡场);

点击查看代码
#pragma GCC optimize("Ofast")
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include <iostream>
#include <cstdio>
using namespace std;
#define FI(n) FastIO::read(n)
#define FO(n) FastIO::write(n)
#define Flush FastIO::Fflush()
namespace FastIO {
    const int SIZE = 1 << 16;
    char buf[SIZE], obuf[SIZE], str[60];
    int bi = SIZE, bn = SIZE, opt;
    inline int read(register char *s) {
        while(bn) {
            for (; bi < bn && buf[bi] <= ' '; bi = -~bi);
            if (bi < bn) break;
            bn = fread(buf, 1, SIZE, stdin);
            bi &= 0;
        }
        register int sn=0;
        while(bn) {
            for (; bi < bn && buf[bi] > ' '; bi = -~bi) s[sn++] = buf[bi];
            if(bi < bn) break;
            bn = fread(buf,1,SIZE,stdin);
            bi &= 0;
        }
        s[sn] &= 0;
        return sn;
    }
    inline bool read(register int &x){
        int n = read(str), bf = 0;
        if(!n) return 0;
        register int i=0;
        (str[i] == '-') && (bf = 1, i = -~i);
		(str[i] == '+') && (i = -~i);
        for (x = 0; i < n; i = -~i) x = (x << 3) + (x << 1) + (str[i] ^ 48);
        bf && (x = ~x + 1);
        return 1;
    }
    inline bool read(register long long &x) {
        int n = read(str), bf = 1;
        if(!n) return 0;
        register int i=0;
        (str[i] == '-') && (bf = -1,i = -~i);
        for (x = 0; i < n; i= -~i) x = (x << 3) + (x << 1) + (str[i] ^ 48);
        (bf < 0) && (x = ~x + 1);
        return 1;
    }
    inline void write(register int x) {
        if(!x) obuf[opt++] = '0';
        else {
            (x < 0) && (obuf[opt++] = '-', x = ~x + 1);
            register int sn = 0;
            while(x) str[sn++] = x % 10 + '0', x /= 10;
            for (register int i = sn - 1; i >= 0; i = ~-i) obuf[opt++] = str[i];
        }
        (opt >= (SIZE >> 1)) && (fwrite(obuf, 1, opt, stdout), opt &= 0);
    }
    inline void write(register long long x) {
        if(!x) obuf[opt++] = '0';
        else {
            (x < 0) && (obuf[opt++] = '-', x = ~x + 1);
            register int sn = 0;
            while(x) str[sn++] = x % 10 + '0', x /= 10;
            for (register int i = sn - 1; i >= 0; i = ~-i) obuf[opt++] = str[i];
        }
        (opt >= (SIZE >> 1)) && (fwrite(obuf, 1, opt, stdout), opt &= 0);
    }
    inline void write(register unsigned long long x){
        if(!x) obuf[opt++] = '0';
        else {
            register int sn=0;
            while(x) str[sn++] = x % 10 + '0', x /= 10;
            for (register int i = sn - 1 ; i >= 0 ; i = ~-i)obuf[opt++] = str[i];
        }
        (opt >= (SIZE >> 1)) && (fwrite(obuf, 1, opt, stdout), opt &= 0);
    }
    inline void write(register char x) {
        obuf[opt++] = x;
        (opt >= (SIZE >> 1)) && (fwrite(obuf, 1, opt, stdout), opt &= 0);
    }
    inline void Fflush(){
        opt && fwrite(obuf, 1, opt, stdout);
        opt &= 0;
    }
}
int t;
int n;
long long a[500005];
struct sss{
	int t, ne;
	long long w;
}e[500005];
int h[500005], cnt;
inline void add(int u, int v, long long ww) {
	e[++cnt].t = v;
	e[cnt].ne = h[u];
	h[u] = cnt;
	e[cnt].w = ww;
}
long long siz[500005];
long long tt;
int rt[500005], tot[2];
namespace top_tr{
	struct sss{
		int ls, rs;
		long long sum;
	}tr[2][6500005];
	inline void push_up(long long s, long long id) {
		tr[s][id].sum = tr[s][tr[s][id].ls].sum + tr[s][tr[s][id].rs].sum;
	}
	void add(long long s, int &id, long long l, long long r, long long pos, long long d) {
		if (!id) id = ++tot[s];
		if (l == r) {
			tr[s][id].sum += d;
			return;
		}
		long long mid = (l + r) >> 1;
		if (pos <= mid) add(s, tr[s][id].ls, l, mid, pos, d);
		else add(s, tr[s][id].rs, mid + 1, r, pos, d);
		push_up(s, id);
	}
	long long merge(int s, long long x, long long y, long long l, long long r) {
		if (!x || !y) return x + y;
		if (l == r) {
			tr[s][x].sum += tr[s][y].sum;
			return x;
		}
		long long mid = (l + r) >> 1;
		tr[s][x].ls = merge(s, tr[s][x].ls, tr[s][y].ls, l, mid);
		tr[s][x].rs = merge(s, tr[s][x].rs, tr[s][y].rs, mid + 1, r);
		push_up(s, x);
		return x;
	}
	long long ask(int s, int id, long long L, long long R, long long l, long long r) {
		if (l > r) return 0;
		if (!id) return 0;
		if (L >= l && R <= r) return tr[s][id].sum;
		long long mid = (L + R) >> 1;
		if (r <= mid) return ask(s, tr[s][id].ls, L, mid, l, r);
		else if (l > mid) return ask(s, tr[s][id].rs, mid + 1, R, l, r);
		else return ask(s, tr[s][id].ls, L, mid, l, mid) + ask(s, tr[s][id].rs, mid + 1, R, mid + 1, r);
	}
}
long long ans;
void sfs(long long x, long long fa) {
	siz[x] = a[x];
	for (long long i = h[x]; i; i = e[i].ne) {
		long long u = e[i].t;
		if (u == fa) continue;
		sfs(u, x);
		siz[x] += siz[u];
		rt[x] = top_tr::merge(0, rt[x], rt[u], 1, tt);
		rt[x + n + 1] = top_tr::merge(1, rt[x + n + 1], rt[u + n + 1], 1, tt);
		top_tr::add(0, rt[x], 1, tt, siz[u], e[i].w * siz[u]);
		top_tr::add(1, rt[x + n + 1], 1, tt, siz[u], e[i].w);
	}
}
void dfs(long long x, long long fa) {
	for (long long i = h[x]; i; i = e[i].ne) {
		long long u = e[i].t;
		if (u == fa) continue;
		top_tr::add(0, rt[0], 1, tt, siz[u], e[i].w * siz[u]);
		top_tr::add(1, rt[0 + n + 1], 1, tt, siz[u], e[i].w);
		top_tr::add(0, rt[1], 1, tt, siz[u], -e[i].w * siz[u]);
		top_tr::add(1, rt[1 + n + 1], 1, tt, siz[u], -e[i].w);
		dfs(u, x);
		top_tr::add(0, rt[0], 1, tt, siz[u], -e[i].w * siz[u]);
		top_tr::add(1, rt[0 + n + 1], 1, tt, siz[u], -e[i].w);
		long long an = 0;
		long long X = siz[u];
		long long Y = siz[1] - siz[u];
		long long sum = 0;
		sum = top_tr::ask(0, rt[u + 2 * n + 1], 1, tt, 1, X / 2);
		long long su = 0;
		su = top_tr::ask(1, rt[u + 3 * n + 1], 1, tt, X / 2 + 1, tt);
		su *= X;
		su -= top_tr::ask(0, rt[u + 2 * n + 1], 1, tt, X / 2 + 1, tt);
		an += sum + su;
		sum = top_tr::ask(0, rt[1], 1, tt, 1, Y / 2) - top_tr::ask(0, rt[u + 2 * n + 1], 1, tt, 1, Y / 2);
		su = top_tr::ask(1, rt[1 + n + 1], 1, tt, Y / 2 + 1, tt) - top_tr::ask(1, rt[u + 3 * n + 1], 1, tt, Y / 2 + 1, tt);
		su *= Y;
		su -= (top_tr::ask(0, rt[1], 1, tt, Y / 2 + 1, tt) - top_tr::ask(0, rt[u + 2 * n + 1], 1, tt, Y / 2 + 1, tt));
		an += sum + su;
		sum = top_tr::ask(0, rt[0], 1, tt, siz[u], Y / 2 + siz[u]);
		long long ss = top_tr::ask(1, rt[0 + n + 1], 1, tt, siz[u], Y / 2 + siz[u]);
		ss *= siz[u];
		sum -= ss;
		long long sss = top_tr::ask(1, rt[0 + n + 1], 1, tt, Y / 2 + siz[u] + 1, tt);
		su = sss;
		su *= Y;
		su -= top_tr::ask(0, rt[0], 1, tt, Y / 2 + siz[u] + 1, tt);
		ss = sss;
		ss *= siz[u];
		su += ss;
		an += sum + su;
		ans = min(ans, an);
		top_tr::add(0, rt[1], 1, tt, siz[u], e[i].w * siz[u]);
		top_tr::add(1, rt[1 + n + 1], 1, tt, siz[u], e[i].w);
		rt[x + 2 * n + 1] = top_tr::merge(0, rt[x + 2 * n + 1], rt[u + 2 * n + 1], 1, tt);
		rt[x + 3 * n + 1] = top_tr::merge(1, rt[x + 3 * n + 1], rt[u + 3 * n + 1], 1, tt);
		top_tr::add(0, rt[x + 2 * n + 1], 1, tt, siz[u], e[i].w * siz[u]);
		top_tr::add(1, rt[x + 3 * n + 1], 1, tt, siz[u], e[i].w);
	}
}
int main() {
	freopen("banking.in", "r", stdin);
	freopen("banking.out", "w", stdout);
	FI(t);
	while(t--) {
		FI(n);
		for (long long i = 1; i <= n; i++) {
			FI(a[i]);
			tt += a[i];
		}
		long long x, y;
		long long w;
		ans = 2e18;
		for (long long i = 1; i <= n - 1; i++) {
			FI(x); FI(y); FI(w);
			add(x, y, w);
			add(y, x, w);
		}
		sfs(1, 0);
		dfs(1, 0);
		FO(ans);
		FO('\n');
		for (long long i = 1; i <= n; i++) {
			h[i] = 0;
		}
		cnt = 0;
		for (long long s = 0; s <= 1; s++) {
			for (long long i = 1; i <= tot[s]; i++) {
				top_tr::tr[s][i].ls = top_tr::tr[s][i].rs = top_tr::tr[s][i].sum = 0;
			}
		}
		for (long long i = 0; i <= 4 * n + 1; i++) {
			rt[i] = 0;
			siz[i] = 0;
		}
		tt = 0;
		tot[0] = tot[1] = 0;
	}
	Flush;
	return 0;
}

标签:rt,赛记,int,siz,tt,tr,long,加赛,NOIP2024
From: https://www.cnblogs.com/PeppaEvenPig/p/18534376

相关文章

  • 多校A层冲刺NOIP2024模拟赛19
    多校A层冲刺NOIP2024模拟赛19其实不太想写博客,但还是从今天开始坚持写吧。T1图书管理对于这种一边大一边小的问题,一般套路是大的设为$1$,小的设为$-1$,这道题也是,这样之后去扫一遍,两端的前缀和值一样即可。T2两棵树新学到的一个重要$trick$是:$$连通块的个数......
  • [63] (多校联训) A层冲刺NOIP2024模拟赛19
    lhx对\((\lnn)^{\lnn}\)求导求出一个形如\(\frac{1}{n\lnn\ln\lnn}\)的东西A.图书管理说一种很好玩的\(n^2\logn\)做法(因为动态中位数我只会这个)对顶堆:就是你开一个大根堆和一个小根堆,然后把它们怼在一起,钦定比中位数大的放小根堆,小的放大根堆,这样中间就是中位......
  • 11月7日 NOIP模拟(难题math、矩阵游戏matrix、括号序列seq、道路road) - 模拟赛记录
    PrefaceT1试图找规律失败,正经推反而几分钟就出来了。以后应该少想这些歪门邪道(除非实在闲的蛋疼或者没有一点头绪,且必须要打完所有能打的子任务比如暴力或特殊性质;而且必须在用常规方法思考过后,才能够用一些稍微不那么常规的方法)至于T2、T3、T4,因为知道T1浪费了太多时间,都是......
  • 多校 A 层冲刺 NOIP2024 模拟赛 19
    题解还是得写,不能偷懒啊~多校A层冲刺NOIP2024模拟赛19图书管理签到题考虑最困难的部分是确定中位数,不妨钦定中位数,然后计算其贡献,然后考虑只枚举一个边界,另一个边界可以放桶里。时间复杂度\(O(n^2)\)。两棵树概率期望考虑拆贡献,有等式\[连通块个数=点数-边数\]证明考虑......
  • 『模拟赛』多校A层冲刺NOIP2024模拟赛19
    RankbydCSP之后就没场切过题......
  • 多校A层冲刺NOIP2024模拟赛19
    讲个笑话:(讨论时间)huge:(叹气)这讨论啊,就是改不了,这换了铃声了,也没……众人:现在是讨论时间啊。huge:(停顿)那刚才大课间那会哇啦哇啦的……图书管理简要题意给定一个长度为\(n(n\le10^4)\)的排列,求\(\sum\limits_{l=1}^n\sum\limits_{r=l}^n[r-l为偶数]l\timesr\timesf_{l,r}\)......
  • 多校A层冲刺NOIP2024模拟赛19
    多校A层冲刺NOIP2024模拟赛19\(T1\)A.图书管理(book)\(90pts/90pts\)部分分\(90pts\):平衡树/线段树、主席树上二分/对顶堆暴力维护中位数,同luoguP3871[TJOI2010]中位数|luoguP1168中位数,时间复杂度为\(O(n^{2}\logn)\),需要适当卡常。点击查看代码in......
  • NOIP2024集训Day71 贪心
    NOIP2024集训Day71贪心B.[CCO2015]饥饿的狐狸显然的,要求出最大美味值,应该先交错吃温度最大的和最小的饼干。所以我们给所有饼干按照温度排序,交替选择左右端点吃,如果喝水能够达到更大那就先喝水再吃,反正水管够。分两种情况,即左右端点谁先开始,再取个\(\operatorname{max}\)。......
  • 多校A层冲刺NOIP2024模拟赛18
    多校A层冲刺NOIP2024模拟赛18T1选彩笔(rgb)签到题,但是没签上。。。没想到三维前缀和,直接上了个bitset。就是直接二分答案,然后枚举这三维每维的区间的起点,前缀和查数量是否大于等于$K$即可,也可以把二分答案改为第一维的双指针,少一个$log$。T2兵蚁排序(sort)比T1还签......
  • CSP2024 前集训:NOIP2024加赛 2
    前言T2开太晚了,没打完,别的没怎么挂。哦对,T1以为埃筛复杂度是\(nlog^2\),实际上是\(n\ln(\ln(n))\),结果以为复杂度是错的,然后本地不开O2都飞快,我甚至还在惊叹本地竟然能跑\(5e9\)……还有我之前不知道树的直径的中点时唯一的……T1新的阶乘直接埃筛做完了。点击查......