2026-01-22~23 hetao1733837 的刷题笔记

2026-01-22~23 hetao1733837 的刷题笔记

01-22

LGP1855 榨取kkksc03

原题链接:榨取kkksc03

分析

背包,多了一维,没啥可说的,记得倒叙枚举。

正解

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 205;
int n, M, T;
struct node{
    int m, t;
}a[N];
int dp[N][N];
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> M >> T;
    for (int i = 1; i <= n; i++){
        cin >> a[i].m >> a[i].t;
    }
    for (int i = 1; i <= n; i++){
        for (int j = M; j >= a[i].m; j--){
            for (int k = T; k >= a[i].t; k--){
                dp[j][k] = max(dp[j][k], dp[j - a[i].m][k - a[i].t] + 1);
            }
        }
    }
    cout << dp[M][T];
}

LGP1757 通天之分组背包

原题链接:通天之分组背包

分析

理论今天最后一题......又周四了,群里居然没有疯四文案......

再多记录一维?分组背包是橙我吃......坏了,真得吃了......
NOIP 考场上的感悟是对的,基础这一块确实很差。

正解

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1005, M = 105, K = 10005;
int n, m, k = 1;
vector<pair<int, int>> inp[K];
int dp[N];
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> m >> n;
    for (int i = 1, a, b, c; i <= n; i++){
        cin >> a >> b >> c;
        k = max(k, c);
        inp[c].push_back({a, b});
    }
    for (int i = 1; i <= k; i++){
        for (int j = m; j >= 0; j--){
            for (auto tmp : inp[i]){
                if (j >= tmp.first){
                    dp[j] = max(dp[j], dp[j - tmp.first] + tmp.second);
                }
            }
        }
    }
    cout << dp[m];
}

01-23

LGP8576 「DTOI-2」星之界

原题链接:「DTOI-2」星之界

分析

区间修改一个线段树就可以搞定,但是,那个神秘式子怎么办?可以做一个前缀和,但是,乘又怎么办?前缀积?似乎不是个好办法......还是说又是一个 Lucas ⁡ \operatorname{Lucas} Lucas 定理?咋™是分块?化简式子!
∏ i = l r ( ∑ j = l i a j a i ) = ( ∑ i = l r a i ) ! ∏ i = l r ( a i ! ) \prod\limits_{i=l}^{r}{\tbinom{\sum\limits_{j=l}^{i}{a_j}}{a_i}}=\frac{(\sum\limits_{i=l}^{r}{a_i})!}{\prod\limits_{i=l}^{r}{(a_i!)}} i=l∏r(aij=l∑iaj)=i=l∏r(ai!)(i=l∑rai)!

维护区间和,区间阶乘之积。考虑分块。呃......我似乎不会......看了 DaidlyNOIP2023 游记,他说的很对,常规难度确实应该加到紫黑,真的,我觉得我们两个在某些方面确实比较像,但是我比他菜 INF 倍......我觉得我不应该追求那么多数量了,fqh 暑假给我说的练得太少,当时确实,但是现在不一样了,现在一定要追求质量!蓝只能作为起步,橙黄绿只能是板子或者娱乐,紫黑才是真正重要的!

数据范围比较大,需要预处理。

然后就是这个题最具启发性的点------分块+并查集。并查集维护的就是值相同的块,然后啊吧啊吧......我要上体育课了。

回来了......结合代码理解亿下......分块还是太折磨入了......

梳理一下,因为维护的信息比较"高级",所以普通的线段树不太行了,必须使用分块。如果每次询问都把整个序列跑一边不太行,所以,套一个并查集,记录每个数所属的桶。

正解

cpp 复制代码
#include <bits/stdc++.h>
#define mod 998244353
using namespace std;
const int N = 100005, M = 10000005, O = 330; //$O=\sqrt{N}$
int n, q, a[N], pre[N];
int fa[N];
int find(int x){
	return x == fa[x] ? x : fa[x] = find(fa[x]);
}
int fac[M], invfac[N];
int mulif[N / O + 5], sum[N / O + 5], invpow[N][O + 5], facpow[N][O + 5];
int id[N / O + 5];
int pos[N / O + 5][N], cnt[N / O + 5][N];
int qpow(int a, int b){
	int res = 1;
	while (b){
		if (b & 1)
			res = 1ll * res * a % mod;
		b >>= 1;
		a = 1ll * a * a % mod;
	}
	return res;
}
void init(){
	fac[0] = invfac[0] = 1;
	for (int i = 1; i < M; i++){
		fac[i] = 1ll * fac[i - 1] * i % mod;
	}
	invfac[N - 5] = qpow(fac[N - 5], mod - 2);
	for (int i = N - 6; i >= 1; i--){
		invfac[i] = 1ll * invfac[i + 1] * (i + 1) % mod;
	}
	for (int i = 0; i < N; i++){
		invpow[i][0] = facpow[i][0] = 1;
		for (int j = 1; j <= O; j++){
			invpow[i][j] = 1ll * invpow[i][j - 1] * invfac[i] % mod;
			facpow[i][j] = 1ll * facpow[i][j - 1] * fac[i] % mod;
		}
	}
}
void clear(int p){
	mulif[p] = 1;
	sum[p] = 0;
	for (int i = id[p - 1] + 1; i <= id[p]; i++){
		cnt[p][a[i]]++;
		if (cnt[p][a[i]] == 1)
			pos[p][a[i]] = i;
		fa[i] = pos[p][a[i]];
		sum[p] += a[i];
		mulif[p] = 1ll * mulif[p] * invfac[a[i]] % mod;
	}
}
void add(int p){
	for (int i = id[p - 1] + 1; i <= id[p]; i++){
		a[i] = a[find(i)];
		pos[p][a[i]] = cnt[p][a[i]] = 0;
	}
}
void modify(int l, int r, int x, int y){
	if (pre[l] == pre[r]){
		add(pre[l]);
		for (int i = l; i <= r; i++){
			if (a[i] == x)
				a[i] = y;
		}
		clear(pre[l]);
		return ;
	}
	if (l != id[pre[l] - 1] + 1){
		add(pre[l]);
		for (int i = l; i <= id[pre[l]]; i++){
			if (a[i] == x)
				a[i] = y;
		}
		clear(pre[l]);
		l = id[pre[l]] + 1;
	}
	if (r != id[pre[r]]){
		add(pre[r]);
		for (int i = id[pre[r] - 1] + 1; i <= r; i++){
			if (a[i] == x)
				a[i] = y;
		}
		clear(pre[r]);
		r = id[pre[r] - 1];
	}
	for (int i = pre[l]; i <= pre[r]; i++){
		if (pos[i][x]){
			if (pos[i][y]){
				fa[pos[i][x]] = pos[i][y];
			}
			else{
				pos[i][y] = pos[i][x];
				a[pos[i][x]] = y;
			}
			sum[i] += (y - x) * cnt[i][x];
			mulif[i] = 1ll * mulif[i] * facpow[x][cnt[i][x]] % mod * invpow[y][cnt[i][x]] % mod;
			cnt[i][y] += cnt[i][x];
			cnt[i][x] = pos[i][x] = 0;
		}
	}
}
int query(int l, int r){
	int s = 0, m = 1;
	if (pre[l] == pre[r]){
		for (int i = l; i <= r; i++){
			a[i] = a[find(i)];
			s += a[i];
			m = 1ll * m * invfac[a[i]] % mod;
		}
		return 1ll * fac[s] * m % mod;
	}
	if (l != id[pre[l] - 1] + 1){
		for (int i = l; i <= id[pre[l]]; i++){
			a[i] = a[find(i)];
			s += a[i];
			m = 1ll * m * invfac[a[i]] % mod;
		}
		l = id[pre[l]] + 1;
	}
	if (r != id[pre[r]]){
		for (int i = id[pre[r] - 1] + 1; i <= r; i++){
			a[i] = a[find(i)];
			s += a[i];
			m = 1ll * m * invfac[a[i]] % mod;
		}
		r = id[pre[r] - 1];
	}
	for (int i = pre[l]; i <= pre[r]; i++){
		s += sum[i];
		m = 1ll * m * mulif[i] % mod;
	}
	return 1ll * fac[s] * m % mod;
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	init();
	cin >> n >> q;
	for (int i = 1; i <= n; i++){
		cin >> a[i];
		fa[i] = i;
	}
	for (int i = 1; i <= n; i++){
		pre[i] = (i + O - 1) / O;
	}
	for (int i = 1; i <= n / O; i++){
		id[i] = i * O;
	}
	if (n % O)
		id[pre[n]] = n;
	else
		id[pre[n]] = n;
	for (int i = 1; i <= pre[n]; i++){
		id[0] = 0;
		clear(i);
	}
	int op, l, r, x, y;
	while(q--){
		cin >> op >> l >> r;
		if (op == 1){
			cin >> x >> y;
			if (x == y)
				continue;
			modify(l, r, x, y);
		}
		else{
			cout << query(l, r) << '\n';
		}
	}
	return 0;
}

LGP8360 [SNOI2022] 军队

原题链接:[SNOI2022] 军队

分析

据说这个题和上面那个题是差不多的......先写个 Trick 本......

哦,那这个似乎更简单一点吧......真的简单吗?似乎这个并查集更......我先上个厕所🚾
我不会也得痔疮了吧......小风帝似乎刚查出来......

哇哦,马上就要启动 BO 了。走了......

上完了,明天结课,感觉可以开整剥削菌笔记了......打算按照每个系统的进化、功能整一个,然后每个门再整对应的纲目科以及对应特点,理论上花的时间应该不少,但是效果应该会不错,过年几天可以整这个,生化的话......我也没想好......没太看出来内在逻辑。

套路一致......开始贺......

贺不完了,先走了。

正解

cpp 复制代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 250005, M = 1010, TMP = 500;
int n, q, C, a[N], c[N], op[N], ql[N], qr[N], qx[N], qy[N];
int fa[N], pa[M], sz[M], col[M];
int val[M], sum, ans[N];
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n >> q >> C;
	for (int i = 1; i <= n; i++){
		cin >> a[i];
	}
	for (int i = 1; i <= n; i++){
		cin >> c[i];
	}
	for (int i = 1; i <= q; i++){
		cin >> op[i] >> ql[i] >> qr[i];
		if (op[i] == 1 || op[i] == 2){
			cin >> qx[i] >> qy[i];
		}
	}
	int cnt = 0;
	for (int l = 1, r; l <= n; l = r + 1){
		r = min(n, l + TMP - 1);
		for (int i = 1; i <= C; i++){
			fa[i] = 0;
		}
		for (int i = l; i <= r; i++){
			val[i - l + 1] = a[i];
			col[i - l + 1] = c[i];
		}
		sum = 0;
		int len = r - l + 1;
		for (int i = len + 1; i <= cnt; i++){
			pa[i] = val[i] = 0;
		}
		cnt = len;
		for (int i = 1; i <= len; i++){
			pa[i] = 0;
			sum += val[i];
			sz[i] = 1;
		}
		for (int i = 1; i <= len; i++){
			if (!fa[col[i]])
				fa[col[i]] = i;
			else{
				int u = fa[col[i]];
				if (u <= len){
					pa[u] = fa[col[i]] = ++cnt;
					u = pa[u];
					sz[u] = 1;
					col[u] = col[i];
				}
				pa[i] = u;
				sz[u]++;
			}
		}
		for (int i = 1; i <= q; i++){
			if (ql[i] <= l && r <= qr[i]){
				if (op[i] == 1){
					if (qx[i] == qy[i] || !fa[qx[i]]){}
					else if (!fa[qy[i]]){
						col[fa[qy[i]] = fa[qx[i]]] = qy[i];
						fa[qx[i]] = 0;
					}
					else{
						int u = ++cnt;
						pa[fa[qy[i]]] = pa[fa[qx[i]]] = u;
						col[u] = qy[i];
						sz[u] = sz[fa[qy[i]]] + sz[fa[qx[i]]];
						fa[qy[i]] = u;
						fa[qx[i]] = 0;
					}
				}
				else if (op[i] == 2){
					if (fa[qx[i]]){
						val[fa[qx[i]]] += qy[i];
						sum += sz[fa[qx[i]]] * qy[i];
					}
				}
				else{
					ans[i] += sum;
				}
			}
			else if (max(ql[i], l) <= min(qr[i], r)){
				for (int j = cnt; j; j--){
					if (pa[j]){
						val[j] += val[pa[j]];
						col[j] = col[pa[j]];
					}
				}
				for (int j = len + 1; j <= cnt; j++){
					pa[j] = val[j] = 0;
				}
				cnt = len;
				for (int j = 1; j <= len; j++){
					fa[col[j]] = 0;
					pa[j] = 0;
				}
				int L = max(ql[i], l) - l + 1, R = min(qr[i], r) - l + 1;
				if (op[i] == 1){
					for (int j = L; j <= R; j++){
						if (col[j] == qx[i])
							col[j] = qy[i];
					}
				}
				else if (op[i] == 2){
					for (int j = L; j <= R; j++){
						if (col[j] == qx[i]){
							val[j] += qy[i];
							sum += qy[i];
						}
					}
				}
				else{
					for (int j = L; j <= R; j++){
						ans[i] += val[j];
					}
				}
				for (int j = 1; j <= len; j++){
					if (!fa[col[j]])
						fa[col[j]] = j;
					else{
						int u = fa[col[j]];
						if (u <= len){
							pa[u] = fa[col[j]] = ++cnt;
							u = pa[u];
							sz[u] = 1;
							col[u] = col[j];
						}
						pa[j] = u;
						sz[u]++; 
					}
				}
			}
		}
	}
	for (int i = 1; i <= q; i++){
		if (op[i] == 3){
			cout << ans[i] << '\n';
		}
	}
	return 0;
}

开始生物?

相关推荐
风筝在晴天搁浅2 小时前
hot100 230.二叉搜索树中第K小的元素
数据结构·算法
curry____3032 小时前
数据结构学习笔记
数据结构·笔记·学习
June bug2 小时前
(#数组/链表操作)寻找两个正序数组的中位数
数据结构·python·算法·leetcode·面试·职场和发展·跳槽
通信小呆呆2 小时前
DDMA MIMO OFDM ISAC:从回波模型到距离-速度图与非相参积累的原理梳理
算法·信息与通信·ofdm·mimo·通信感知一体化
王燕龙(大卫)2 小时前
linuxptp时间同步
c++
leo__5202 小时前
电动助力转向(EPS)系统Simulink模型构建与应用
算法
TracyCoder1232 小时前
LeetCode Hot100(8/100)—— 438. 找到字符串中所有字母异位词
算法·leetcode
郝学胜-神的一滴2 小时前
深入理解Linux套接字(Socket)编程:从原理到实践
linux·服务器·开发语言·网络·c++·程序人生·算法