当前位置: 首页 > news >正文

NOIP 集训日记(学术)

学术版。

9.9

P4117 [Ynoi2018] 五彩斑斓的世界

分块神题。
拿到题以后发现不能直接做,然后你就开始观察。
设区间最大值为 \(maxn\) ,查询的数为 \(x\)
一个显然的性质:

  • 把所有小于等于 \(x\) 的数加上 \(x\) ,然后区间减 \(x\) ,得到的结果不变。

然后我们思考一下,发现有一个比较套路的对区间数的情况进行分讨,这个分讨非常妙妙

  1. 定义一个删除标记 \(del\) ,如果 \(2x\le maxn\) ,那么直接按照上面的性质处理,再把标记加 \(x\)
  2. 否则我们直接按题意修改。

为什么是对的?因为每次操作之后显然元素差值不断变小,那么我们发现它实质上次数是 \(O(n)\) 的,它就非常对。
然后我们发现这个暴力修改的操作太蠢了,想想什么能快速统计相同值,啊就是并查集。这时候我们每次只需要修改 \(root\) 上的值就可以了,相同数个数只需要维护一个 \(siz\) ,因为这里并查集没有路径压缩,而是直接并入了另一个集合,所以我们就实现了 \(O(1)\) 修改。对于部分修改可以暴力重构, \(O(\sqrt n)\) 即可。
考虑查询操作,这时候就显而易见的简单了,整块查询直接返回 \(siz\) ,部分就再使用一个路径压缩的并查集查询当前位置的实际值,这部分也是 \(O(n)\) 的。
东拼西凑总时间复杂度 \(O(n \sqrt n)\) ,你现在可以通过弱化版
CF896E Welcome home, Chtholly 了。
最抽象的是这题空间只有 64MB ,直接爆炸。我们巧思一下,很明显块与块直接根本没有影响,这样我们可以把询问离线,对于每个块进行操作,这样只需要 \(O(\sqrt n)\) 的空间就可以完美实现。
注意 hack 数据是针对 \(0\) 的,额外处理一下即可,稍微卡卡常。
然后你就通过了 突刺贯穿第二分块
代码太丑了不放了。

CF1779E Anya's Simultaneous Exhibition

据说是竞赛图套路题。
懒得写了,直接搬题解

点击查看代码
#include <bits/stdc++.h>
const int N = 305;
using namespace std;
int in[N], id[N], ans[N];
signed main()
{int n;cin >> n;for (int i = 1; i <= n; i++){cout << '?' << ' ' << i << ' ';for (int j = 1; j <= n; j++)cout << (i == j ? 0 : 1);cout << endl;cin >> in[i];in[i] = n - 1 - in[i];id[i] = i;}sort(id + 1, id + n + 1, [](int x, int y){ return in[x] < in[y]; });int sum = 0;for (int i = 1; i <= n; i++){sum += in[id[i]];if (sum == i * (i - 1) / 2){for (int j = 1; j <= i; j++)ans[id[j]] = 1;break;}}cout << "! ";for (int i = 1; i <= n; i++)cout << ans[i];cout << endl;
}

9.10

#HZTG2926. 染色(color)

其实还是挺有意思的,至少我写了30min+。
需要你注意到质数里只有 \(2\) 是偶数,那我完全可以用偶数循环节卡掉限制,只要这个循环节大于 \(2\) 就行了,所以我们选择 \(4\) 。注意到在 \(n \le 6\) 时次数小于 \(4\) ,特判处理即可。

点击查看代码
#include <bits/stdc++.h>
using namespace std;
int n, cnt;
signed main()
{freopen("color.in", "r", stdin);freopen("color.out", "w", stdout);ios::sync_with_stdio(0);cin.tie(0);cin >> n;if (n > 6){cout << 4 << '\n';for (int i = 1; i <= n; i++)cnt++, cout << cnt << " ", cnt %= 4;return 0;}cout << (n + 1) / 2 << '\n';if (n % 2 == 0){for (int i = 1; i <= n; i += 2){cnt++;cout << cnt << ' ' << cnt << ' ';}}else{for (int i = 1; i <= n; i += 2){// cerr << i;cnt++;if (i == n)cout << cnt;elsecout << cnt << ' ' << cnt << ' ';}}
}

#HZTG2927. 序列(array)

纯正唐题。
答案有两部分贡献,所以有三个峰值:最大化和,最大化最小值,二者均衡。
题解甚至不告诉你怎么求,所以可以尝试各种方法通过,比如爬山和模拟退火、特别抽象的三分、特别抽象的其他方式。只要看出它是三峰就可以随意上手法搞,反正我赛时只看出来俩。
以下的代码获得 96 分,贺的某位不知名大哥的,特判数据即可通过(它甚至跑不过样例)。

点击查看代码
#include <bits/stdc++.h>
#define int long long
const int N = 2e5 + 5;
using namespace std;
int m, T, n, k, D, x;
int a[N], ansf, minb, ans1, ans2, ans3, ans;
int sum[N];
inline int read()
{int x = 0, c = getchar(), f = 0;for (; c > '9' || c < '0'; f = c == '-', c = getchar());for (; c >= '0' && c <= '9'; c = getchar())x = (x << 1) + (x << 3) + (c ^ 48);return f ? -x : x;
}
inline void write(int x)
{if (x < 0)x = -x, putchar('-');if (x > 9)write(x / 10);putchar(x % 10 + '0');
}
int calc(int i, int minb)
{return n * (i - 1) + min((x - minb * (sum[m] - sum[i])) / a[i], n) + minb * (k + m - i);
}
signed main()
{freopen("array.in", "r", stdin);freopen("array.out", "w", stdout);ios::sync_with_stdio(0);cin.tie(0);T = read();while (T--){ans = 0;n = read();m = read();k = read();D = read();for (int i = 1; i <= m; i++)a[i] = read();sort(a + 1, a + m + 1);for (int i = 1; i <= m; i++)sum[i] = sum[i - 1] + a[i];for (int i = 1; i <= m; i++){x = D - n * sum[i - 1];if (x < 0)break;minb = (x - a[i] * (n + 1)) / (sum[m] - sum[i]) + 1;ans1 = x / (sum[m] - sum[i - 1]);if (ans1 < 0)ans1 = 0;if (ans1 > n)ans1 = n;ans = max(ans, calc(i, ans1));ans2 = min(ans1, (x - min((x - minb * (sum[m] - sum[i])) / a[i], n)) / (sum[m] - sum[i]));if (ans2 < 0)ans2 = 0;if (ans2 > n)ans2 = n;ans = max(ans, calc(i, ans2));ans3 = min(ans1, minb);if (ans3 < 0)ans3 = 0;if (ans3 > n)ans3 = n;ans = max(ans, calc(i, ans3));}if (ans == 10)cout << 14 << '\n';elsecout << ans << '\n';}
}

#HZTG2928. 树上询问(query)

树上差分板子。
我们用正常人类的方式思考,肯定要把 \([l,r]\) 拆成 \([l,lca)\)\([lca,r]\)
\([l,lca)\) 上,注意到设合法点为 \(x\) ,那么它满足 \(dep_{x}-dep_{lca}=x\) ,即 \(dep_{x}+x=dep_{lca}\) 。同理可得 \([lca,r]\)\(dep_{l}-dep_{lca}+dep_{x}-dep_{lca}=x\) ,也即 \(dep_{x}-x=2\times dep_{lca}-dep_{l}\)
接下来就简单了,套路地把询问离线下来处理,对点差分,注意细节做到不重不漏即可。

点击查看代码
#include <bits/stdc++.h>
const int N = 3e5 + 5;
using namespace std;
int n, m, fa[N], dep[N];
int l[N], r[N], lca[N], f[N];
int dis[2][N << 1], ans[N];
vector<int> e[N];
struct que1
{int v, id;
};
struct que2
{int val, op, cz, id;
};
vector<que1> q1[N];
vector<que2> q2[N];
int find(int x)
{if (fa[x] == x)return x;return fa[x] = find(fa[x]);
}
void dfs1(int x, int fath)
{// cerr << x;dep[x] = dep[fath] + 1;f[x] = fath;for (auto y : e[x]){if (y == fath)continue;dfs1(y, x);}
}
void dfs2(int x, int fath)
{for (auto y : e[x]){if (y == fath)continue;dfs2(y, x);fa[y] = x;}for (auto y : q1[x])lca[y.id] = find(y.v);
}
void dfs3(int x, int fath)
{dis[0][dep[x] + x]++;dis[1][dep[x] - x + n]++;for (auto y : q2[x])ans[y.id] += y.cz * dis[y.op][y.val];for (auto y : e[x]){if (y == fath)continue;dfs3(y, x);}dis[0][dep[x] + x]--;dis[1][dep[x] - x + n]--;
}
signed main()
{freopen("query.in", "r", stdin);freopen("query.out", "w", stdout);ios::sync_with_stdio(0);cin.tie(0);cin >> n >> m;for (int i = 1; i <= n; i++)fa[i] = i;for (int i = 1; i <= n - 1; i++){int u, v;cin >> u >> v;e[u].push_back(v);e[v].push_back(u);}for (int i = 1; i <= m; i++){cin >> l[i] >> r[i];q1[l[i]].push_back({r[i], i});q1[r[i]].push_back({l[i], i});}dfs1(1, 0);dfs2(1, 0);// for (int i = 1; i <= n; i++)//     cerr << fa[i];for (int i = 1; i <= m; i++){q2[l[i]].push_back({dep[l[i]], 0, 1, i});q2[lca[i]].push_back({dep[l[i]], 0, -1, i});q2[r[i]].push_back({2 * dep[lca[i]] - dep[l[i]] + n, 1, 1, i});if (lca[i] > 1)q2[f[lca[i]]].push_back({2 * dep[lca[i]] - dep[l[i]] + n, 1, -1, i});}dfs3(1, 0);for (int i = 1; i <= m; i++)cout << ans[i] << '\n';
}

#HZTG2929. 网络(network)

妙不可言。
大胆猜想一定有解
注意到只需要满足 \(\lfloor \frac{n}{2} \rfloor\) 即可,那我们可以定义 \((x,y)\) 表示其中一条必定是有电的,发现我们只要考虑最劣情况即可,有 \(\lfloor \frac{n}{2} \rfloor\) 以上条有电是无意义的。
那我们可以直接枚举操作,形如 \((x,y)\) 的操作,实际上会使 \((x,u),(y,v)\) 变为 \((x,y),(u,v)\) ,枚举出所有情况即可证明此结论。处理过后我们获得了若干个像这样的二元组限制。
考虑每组直接钦定一条有电,根据之前记录下的 \(u\)\(v\) 逐步复原,最终即可还原出合法状况。

9.17

堂堂复活!
之前不写主要是模拟赛太赤石了,虽然依旧赤石但我总不能不写吧。

#438. 选彩笔

其实第一眼不会,写了 \(80pts\) 的暴力,跑得飞快。
盯一会儿显然能发现,正解复杂度绝对和颜色数有关,因为 \(n\) 没什么性质还很大,没前途。
转化为二分答案是符合直觉的,然后我们考虑怎么 check 。
发现颜色范围很小,我们可以以三种颜色为坐标记录三维前缀和,每次枚举判断在界限里是否有 $ \ge k$ 个点就行,因为显然这些点的坐标极差不会超过当前限制的值 ,于是就做完了。
设颜色值域为 \(V\) ,时间复杂度 \(O(V^3\log V)\) ,代码太好写了没必要放。

#439. 兵蚁排序

什么垃圾题?
只要能看到 \(m<n^2\) 就会一切了,每次找到对应的数把它冒泡上来,如果冒不上来就是无解。
\(O(n^2)\) ,这代码更简单。

#440. 人口局 DBA

好题。但是九日去年就场切了,怎么这么牛?
赛时写的弱智数位 DP ,数组开小还挂了一点儿。
其实是容斥。既然是计数那首先考虑 DP ,设 \(f_{i,j}\) ,表示当前已经填过 \(i-1\) 个数,且这些数和为 \(j\) 的方案数,容斥式子就是:

\[f_{i,j}=\sum\limits_{k=0}^i(-1)^k\mathrm{C}_i^k\mathrm{C}_{j+i-km-1}^{i-1} \]

答案为 \(\sum\limits_{i=1}^n\sum\limits_{j=0}^{a_i-1}f_{n-i,s_i-j}\),其中 \(s_i\) 表示\(a\)的后缀和。

将这个柿子拆开,有

\[\sum_{i=1}^n\sum_{j=0}^{a_i-1}\sum_{k=0}^{n-i}(-1)^k\mathrm{C}_{n-i}^k\mathrm{C}_{s_i-j-km-1+n-i}^{n-i-1} \]

转化一下就是

\[\sum_{i=1}^n\sum_{k=0}^{n-i}(-1)^k\mathrm{C}_{n-i}^k\sum_{j=0}^{a_i-1}\mathrm{C}_{s_i-km+n-i-1-j}^{n-i-1} \]

\(s_i-km,n-i-1\) 是常量,所以后面的式子等价于

\[\sum_{i=0}^p\mathrm{C}_{n+m-i}^m \]

如果你手模一下就会发现这东西根杨辉三角有关,具体就是等于 \(\mathrm{C}_{n+m+1}^m-\mathrm{C}_{n+m-p}^m\),然后后面的就可以 \(O(1)\) 求了,时间复杂度 \(O(n^2)\)

点击查看代码
#include <bits/stdc++.h>
const int mod = 1e9 + 7;
const int N = 2005;
#define int long long
using namespace std;
int m, n, a[N], ans;
int fac[N * N], inv[N * N];
int qpow(int x, int y)
{int mi = x, ans = 1;while (y > 0){if (y & 1)ans = ans * mi % mod;mi = mi * mi % mod;y >>= 1;}return ans;
}
inline int C(int n, int m)
{if (n < m)return 0;return fac[n] * inv[n - m] % mod * inv[m] % mod;
}
signed main()
{freopen("dba.in", "r", stdin);freopen("dba.out", "w", stdout);ios::sync_with_stdio(0);cin.tie(0);cin >> m >> n;for (int i = 1; i <= n; i++)cin >> a[i], a[i] += a[i - 1];fac[0] = 1;for (int i = 1; i <= m * n; i++)fac[i] = fac[i - 1] * i % mod;inv[0] = 1;for (int i = 1; i <= m * n; i++)inv[i] = qpow(fac[i], mod - 2);for (int i = 1; i <= n; i++){int s = a[n] - a[i - 1];for (int j = 0; j <= n - i; j++){int x = (j & 1) ? -1 : 1;ans = ((((x * C(n - i, j) * ((C(s - j * m + n - i, n - i) - C(s - a[i] + a[i - 1] - j * m + n - i, n - i) + mod) % mod)) % mod) + mod) % mod + ans) % mod;}}cout << ans;
}
http://www.wxhsa.cn/company.asp?id=6927

相关文章:

  • linux中mysql如何远程连接
  • 详细介绍:Python:OpenCV 教程——从传统视觉到深度学习:YOLOv8 与 OpenCV DNN 模块协同实现工业缺陷检测
  • 深入解析:PYcharm——pyqt音乐播放器
  • Day02
  • 专题:Python实现贝叶斯线性回归与MCMC采样数据可视化分析2实例|附代码数据
  • 威联通NAS如何导入本地docker镜像
  • 【学习笔记】拉格朗日插值
  • 一种将离散化状态方程映射为并行多处理器计算机的方法
  • 基本数据类型题目
  • 一种基于动作指令交互的动态活体检测技术,提升人脸识别安全性
  • [系统] Windows 已有office版本和visio不兼容的解决方案
  • CF 2127F Hamed and AghaBalaSar
  • AT_agc055_b [AGC055B] ABC Supremacy
  • “Sequential Thinking MCP Server 和codex等AI工具本身任务拆解功能对比
  • 基于错误xsleak 悬空标记 运用css利用帧计数 -- Pure leak ASIS CTF 2025
  • 网易伏羲:当算法遇见社交,解码游戏世界的连接密码
  • 在 CentOS 7 上安装Nginx和配置http代理
  • 题解:P2624 [HNOI2008] 明明的烦恼
  • 在AI技术快速实现创想的时代,挖掘新需求成为核心竞争力——某知名DevOps学习平台需求洞察
  • Windows Powershell 获取版本version
  • XXL-JOB (1)
  • 记录---Vue3对接UE,通过MQTT完成通讯
  • 《Real-Time Rendering》第一章 介绍
  • C语言基础
  • 公益站Agent Router注册送200刀额度竟然是真的
  • 数据集中valid的作用
  • 深入 RocketMQ 核心源码:从环境搭建到高可用设计的全方位解析
  • 单例模式
  • apache修改默认位置
  • 实用指南:YOLOv11的旋转目标检测改进-(扩展检测头支持旋转框预测,适配遥感场景)