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)!
维护区间和,区间阶乘之积。考虑分块。呃......我似乎不会......看了 Daidly 的 NOIP2023 游记,他说的很对,常规难度确实应该加到紫黑,真的,我觉得我们两个在某些方面确实比较像,但是我比他菜 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;
}
开始生物?