『模拟赛』NOIP2024加赛8

Rank

image

A. flandre

签。

比较显然,由于 \(k\ge 0\),所以最终的序列一定为不降序列。首先将原序列升序排序,当任取一个子序列时,容易发现最后一个数越大一定越优,那么最后一个数取到最大值时,倒数第二个数一定越大越优,以此类推,最终取出的序列一定是原序列的一个后缀。我们倒序枚举逐个选择,当选了某个烟花答案变得不优时结束选择即可。复杂度瓶颈是排序的 \(\mathcal{O(n\log n)}\)

说句闲话:四个核的虚拟机跑大样例要 1s 多,换成 DEV 或者本机 vscode 只用 0.3s。

点击查看代码
#include<bits/stdc++.h>
#define fo(x, y, z) for(int (x) = (y); (x) <= (z); (x)++)
#define fu(x, y, z) for(int (x) = (y); (x) >= (z); (x)--)
using namespace std;
typedef long long ll;
#define lx ll
inline lx qr()
{char ch = getchar(); lx x = 0, f = 1;for(; ch < '0' || ch > '9'; ch = getchar()) if(ch == '-') f = -1;for(; ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 3) + (x << 1) + (ch ^ 48);return x * f;
}
#undef lx
#define qr qr()
#define fi first
#define se second
#define pii pair<int, int>
#define P_B(x) push_back(x)
#define M_P(x, y) make_pair(x, y)
const int Ratio = 0;
const int N = 1e6 + 5;
int n, k;
int a[N], id[N];
ll ans;
int st[N], top;
namespace Wisadel
{ll zc[N], zct;inline void Wqw(ll x){if(!x){putchar('0'); return ;}while(x) zc[++zct] = x % 10, x /= 10;while(zct) putchar(zc[zct--] + '0');}short main(){freopen("flandre.in", "r", stdin), freopen("flandre.out", "w", stdout);n = qr, k = qr;fo(i, 1, n) a[i] = qr, id[i] = i;sort(id + 1, id + 1 + n, [](int A, int B){return a[A] > a[B];});int tot = 0, nowtot = 0;fo(i, 1, n){if(i == 1) nowtot = 1;else if(nowtot && a[id[i]] != a[st[top]]) tot += nowtot, nowtot = 1;else if(nowtot && a[id[i]] == a[st[top]]) nowtot++;ll zc = ans + 1ll * k * tot + a[id[i]];if(zc >= ans) ans = zc, st[++top] = id[i];else break;}Wqw(ans), putchar(' '), Wqw(top), puts("");while(top) Wqw(st[top--]), putchar(' ');puts("");return Ratio;}
}
signed main(){return Wisadel::main();}

B. meirin

这题没切纯唐了。

所求答案可以化成形如 \(\sum_{i=1}^n (x_1a_1+x_2a_2+\cdots +x_na_n)b_i\) 的形式。发现 \(a_i\) 是不变的,我们只要求出每个 \(b_i\) 前的系数,然后搬到线段树上就做完了。问题就在求这个系数上。赛时一直在拆分到每个 \(a_i\) 前的系数上,导致无论怎么优化都只能达到 \(\mathcal{O(n^2)}\) 求。

发现单点求是没有前途的,我们考虑对一个区间求。如下图,我们求点 \(i\) 的系数贡献,本质上是求所有包含点 \(i\) 的区间的 \(a_i\) 之和。

image

考虑枚举左侧的区间,那么其可以对应的是右侧所有区间,记录前缀和的前缀和,可以对每一个左侧区间 \(\mathcal{O(1)}\) 求出贡献。同理,对于每个右侧的区间,其可以对应的是左侧所有区间,记录后缀和的后缀和,可以 \(\mathcal{O(1)}\) 求出。那么对于每个点做一次求出系数预处理,复杂度就来到了 \(\mathcal{O(n)}\)。那么每次修改,只需区间和求出对应的系数和,就可以直接求出结果。时间复杂度是 \(\mathcal{O(n+q\log n)}\)

注意预处理时边界的处理。

点击查看代码
#include<bits/stdc++.h>
#define fo(x, y, z) for(int (x) = (y); (x) <= (z); (x)++)
#define fu(x, y, z) for(int (x) = (y); (x) >= (z); (x)--)
using namespace std;
typedef long long ll;
#define lx ll
inline lx qr()
{char ch = getchar(); lx x = 0, f = 1;for(; ch < '0' || ch > '9'; ch = getchar()) if(ch == '-') f = -1;for(; ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 3) + (x << 1) + (ch ^ 48);return x * f;
}
#undef lx
#define qr qr()
#define fi first
#define se second
#define pii pair<int, int>
#define P_B(x) push_back(x)
#define M_P(x, y) make_pair(x, y)
const int Ratio = 0;
const int N = 5e5 + 5;
const int mod = 1e9 + 7;
int n, q;
ll a[N], b[N];
ll v[N << 2], zz[N];
ll s[N], ss[N], h[N], hh[N]; 
namespace Wisadel
{#define ls (rt << 1)#define rs (rt << 1 | 1)#define mid ((l + r) >> 1)inline void Wpushup(int rt){v[rt] = (v[ls] + v[rs]) % mod;}inline void Wbuild(int rt, int l, int r){if(l == r){v[rt] = zz[l];return ;}Wbuild(ls, l, mid), Wbuild(rs, mid + 1, r);Wpushup(rt);}inline ll Wq(int rt, int l, int r, int x, int y){if(x <= l && r <= y) return v[rt];ll res = 0;if(x <= mid) res = (res + Wq(ls, l, mid, x, y)) % mod;if(y > mid) res = (res + Wq(rs, mid + 1, r, x, y)) % mod;return res;}short main(){freopen("meirin.in", "r", stdin), freopen("meirin.out", "w", stdout);n = qr, q = qr;fo(i, 1, n) a[i] = qr;fo(i, 1, n) b[i] = qr;fo(i, 1, n) s[i] = (s[i - 1] + a[i]) % mod;fu(i, n, 1) h[i] = (h[i + 1] + a[i]) % mod;fo(i, 1, n) ss[i] = (ss[i - 1] + s[i]) % mod; fu(i, n, 1) hh[i] = (hh[i + 1] + h[i]) % mod;ll ans = 0;fo(i, 1, n){ll zc = ((ss[n] - ss[i - 1] + mod) % mod - s[i - 1] * (n - i + 1) % mod + mod) % mod * i % mod;zc = (zc + ((hh[1] - hh[i] + mod) % mod - h[i] * (i - 1) % mod + mod) % mod * (n - i + 1) % mod) % mod;zz[i] = zc;ans = (ans + zz[i] * b[i] % mod) % mod;}Wbuild(1, 1, n);fo(i, 1, q){int l = qr, r = qr; ll k = (qr % mod + mod) % mod;ll zc = Wq(1, 1, n, l, r) * k % mod;ans = (ans + zc) % mod;printf("%lld\n", ans);}return Ratio;}
}
signed main(){return Wisadel::main();}

C. sakuya

比较诈骗,赛时题面把大家都吓住了。

考虑期望的本质是所有方案代价的平均数,我们对于每条边统计其贡献,求和之后除以方案数即可。对于每一条边,考虑统计其代价的充要条件是在其连接的两个连通块中,各存在一个特殊点且要求二者在序列中相邻。那么设其中一端的子树内有 \(s\) 个特殊点,则另一端有 \(m-s\) 个特殊点,可能的方案数共有 \(2s(m-s)\) 个(双向)。将其提出到序列中,它们可以在序列中的任意地方出现,故方案数乘上 \(m-1\),同时其他 \(m-2\) 个特殊点的顺序不做要求,故还要乘上 \((m-2)!\)。最后乘上其边权就得出了这条边的贡献。

考虑加入修改如何做。将上述边贡献中 \(2s(m-s)(m-1)(m-2)!\) 看做系数,统计每个点所连边的系数之和,容易发现给这个点所连边加边权等价于给系数之和乘上 \(k\) 加入答案,那么就做完了。直接 dfs 求出每个点子树内特殊点数量,然后处理每条边即可。时间复杂度 \(\mathcal{O(n+q)}\)

点击查看代码
#include<bits/stdc++.h>
#define fo(x, y, z) for(int (x) = (y); (x) <= (z); (x)++)
#define fu(x, y, z) for(int (x) = (y); (x) >= (z); (x)--)
using namespace std;
typedef long long ll;
#define lx ll
inline lx qr()
{char ch = getchar(); lx x = 0, f = 1;for(; ch < '0' || ch > '9'; ch = getchar()) if(ch == '-') f = -1;for(; ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 3) + (x << 1) + (ch ^ 48);return x * f;
}
#undef lx
#define qr qr()
#define fi first
#define se second
#define pii pair<int, int>
#define P_B(x) push_back(x)
#define M_P(x, y) make_pair(x, y)
const int Ratio = 0;
const int N = 5e5 + 5;
const int mod = 998244353;
int n, m, q;
int b[N], siz[N];
int hh[N], to[N << 1], ne[N << 1], cnt = 1;
ll qzs[N << 1], f[N], ans, jc[N];
namespace Wisadel
{inline ll Wqp(ll x, int y){ll res = 1;while(y){if(y & 1) res = res * x % mod; x = x * x % mod; y >>= 1;}return res;}inline void Wadd(int u, int v, ll val){to[++cnt] = v;qzs[cnt] = val;ne[cnt] = hh[u];hh[u] = cnt;}inline void Wdfs(int u, int fa){siz[u] = b[u];for(int i = hh[u]; i != -1; i = ne[i]){int v = to[i];if(v == fa) continue;Wdfs(v, u);siz[u] += siz[v];ll zc = 2ll * siz[v] * (m - siz[v]) % mod * (m - 1) % mod * jc[m - 2] % mod;f[u] = (f[u] + zc) % mod, f[v] = (f[v] + zc) % mod;ans = (ans + zc * qzs[i] % mod) % mod;}}short main(){freopen("sakuya.in", "r", stdin), freopen("sakuya.out", "w", stdout);n = qr, m = qr;jc[0] = 1; fo(i, 1, m) jc[i] = jc[i - 1] * i % mod;memset(hh, -1, sizeof hh);fo(i, 1, n - 1){int a = qr, b = qr; ll c = qr;Wadd(a, b, c), Wadd(b, a, c);}fo(i, 1, m) b[qr] = 1;Wdfs(1, 0);q = qr;fo(i, 1, q){int x = qr; ll k = qr;ans = (ans + f[x] * k % mod) % mod;printf("%lld\n", ans * Wqp(jc[m], mod - 2) % mod);}return Ratio;}
}
signed main(){return Wisadel::main();}

D. 红楼 ~ Eastern Dream

容易发现模数和区间修改的段数有关,模数越大段数越小。首先考虑根号分治。对于小于 \(\sqrt{n}\) 的模数,我们记录每个模数对应的循环中所有位置的修改值并对其做前缀和处理,那么我们查询时只用遍历这 \(\sqrt{n}\) 个模数,分讨求出该区间新加的值之和即可。

对于大于 \(\sqrt{n}\) 的模数,容易想到线段树处理,可这样依然会对至多 \(\sqrt{n}\) 个区间做修改,修改复杂度是 \(\mathcal{O(n\log n\sqrt{n})}\) 的,查询是 \(\mathcal{O(n\log n)}\) 的。

发现修改和查询复杂度比例为 \(\sqrt{n}\),因此考虑根号平衡。直接对序列分块。发现我们要做到 \(\mathcal{O(1)}\) 查询,因此考虑差分实现,维护每一块的差分数组之和。画出图来发现每一块的贡献是一个矩形加上一个三角形的面积。矩形的一条边是询问区间长度,另一条边长度就是差分数组和。而三角形的形状是不变的,直接维护三角形面积即可。考虑怎么修改。对矩形边的修改是平凡的,对三角形的修改,考虑底变了,高不变,因此直接乘上高加入面积即可。之后就是平凡的分块操作,然后就做完了。整体复杂度 \(\mathcal{O(n\sqrt{n})}\)

点击查看代码
#include<bits/stdc++.h>
#define fo(x, y, z) for(int (x) = (y); (x) <= (z); (x)++)
#define fu(x, y, z) for(int (x) = (y); (x) >= (z); (x)--)
using namespace std;
typedef long long ll;
#define lx ll
inline lx qr()
{char ch = getchar(); lx x = 0, f = 1;for(; ch < '0' || ch > '9'; ch = getchar()) if(ch == '-') f = -1;for(; ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 3) + (x << 1) + (ch ^ 48);return x * f;
}
#undef lx
#define qr qr()
#define fi first
#define se second
#define pii pair<int, int>
#define P_B(x) push_back(x)
#define M_P(x, y) make_pair(x, y)
const int Ratio = 0;
const int N = 2e5 + 5, NN = 450;
int n, m;
int a[N];
int bl[N], ed[N], sq;
ll s1[N], s2[N], lazy, f[NN][NN], c[N];
namespace Wisadel
{inline void Wupd(int x, ll k){int zc = bl[x];c[x] += k, s1[zc] += k, s2[zc] += k * (ed[zc] - x + 1);}inline ll Wq(int l, int r){ll res = 0;fo(i, 1, bl[l] - 1) res += s1[i] * (r - l + 1);fo(i, ed[bl[l] - 1] + 1, l - 1) res += c[i] * (r - l + 1);if(bl[r] - bl[l] <= 1){fo(i, l, r) res += c[i] * (r - i + 1);}else{fo(i, l, ed[bl[l]]) res += c[i] * (r - i + 1);fo(i, bl[l] + 1, bl[r] - 1) res += s1[i] * (r - ed[i]) + s2[i];fo(i, ed[bl[r] - 1] + 1, r) res += c[i] * (r - i + 1);}return res;}short main(){freopen("scarlet.in", "r", stdin), freopen("scarlet.out", "w", stdout);n = qr, m = qr;fo(i, 1, n) a[i] = qr, c[i] = a[i] - a[i - 1];sq = sqrt(n);fo(i, 1, sq) ed[i] = n / sq * i;ed[sq] = n;fo(i, 1, sq) fo(j, ed[i - 1] + 1, ed[i]) bl[j] = i, s1[i] += c[j], s2[i] += 1ll * c[j] * (ed[i] - j + 1);fo(i, 1, m){int op = qr, l = qr, r = qr; ll k;if(op == 1){k = qr;if(l <= r + 1) lazy += k;else if(l < sq){ll zc = 0;fo(j, 0, r) zc += k, f[l][j] += zc;fo(j, r + 1, l - 1) f[l][j] += zc;}else{for(int j = 0; j < n; j += l){Wupd(j + 1, k);if(j + 1 + r + 1 <= n) Wupd(j + 2 + r, -k);}}} else{ll ans = lazy * (r - l + 1);fo(j, 1, sq - 1){int tim = ((r - 1) / j) - ((l + j - 1) / j);if(tim > 0) ans += f[j][j - 1] * tim;int L = (l - 1 + j) % j, R = (r - 1 + j) % j;if((r - 1) / j == (l - 1) / j) ans -= f[j][j - 1];ans += f[j][j - 1] - (L ? f[j][L - 1] : 0) + f[j][R];}ans += Wq(l, r);printf("%lld\n", ans);}}return Ratio;}
}
signed main(){return Wisadel::main();}

赛时状态一般,T2 一直没往区间和上想属实是唐了。T3 被题面吓到没敢深究,T4 打的暴力喜提 70pts。

NOIP 这样的状态真就 G 了。考前打这样一场模拟赛也算是长教训。研究题不能只在一个方向上搞。点不行想线,线要再扩展到面。全面地研究每道题,才能得出真正优的解法。

以及细节处理上,T1 上来就打,越打越发现有些东西没处理,然后改来改去错失首 A。好在这只是签,码短好调,如果在一道码力题上犯这样的错,可能错失的就是 100pts 了。Think twice, code once.

还剩一场终结赛,全力以赴,打出气势。


完结撒花~

~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/842515.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

manim边做边学--圆柱体

Cylinder是Manim中用于创建圆柱体对象的类。 Cylinder类在制作数学、物理或工程领域的动画时,可用于以下的场景中:演示几何概念:使用Cylinder类创建圆柱体,并通过改变其参数和方法来演示圆柱体的各种几何性质,如体积、表面积等。 模拟物理现象:使用Cylinder类来模拟圆柱体…

基于Java+SpringBoot+Mysql在线简单拍卖竞价拍卖竞拍系统功能设计与实现十一

运行环境:windows/Linux均可、jdk1.8、mysql5.7、redis3.0、idea/eclipse均可。 技术点:SpringBoot+SpringDataJPA+Mysql+Freemaker+Bootstrap+JS+CSS+HTML 部分功能:前台竞价商品信息控制器Controller(商品列表、商品详情、报名、拍价、查看报名记录等 )一、前言介绍: 免…

Docker 实战:搭建本地 Registry 私有镜像仓库及批量导入脚本

前言:在我之前的博客中,我分享了 Harbor 仓库搭建的详细操作步骤。然而,在实际的生产环境中,并非每个 Docker 环境都需要部署一个规模庞大的 Harbor 仓库。有时,一个轻量级的本地 Registry 私有镜像仓库会更为便捷。本文将介绍如何搭建一个本地 Registry 私有镜像仓库,并…

Chrome联合Opera/Vivaldi/Waterfox等成立联盟对抗Microsoft Edge

日前在欧盟有个新的行业联盟成立,这个行业联盟名为浏览器选择联盟,主要成员包括 Google Chrome、Opera、Vivaldi、Waterfox 和 Wavebox。 成立联盟的主要目的是对抗微软的 Microsoft Edge 浏览器,该联盟致力于呼吁 / 游说欧盟将 MicROSoft Edge 按照数字市场法案列为看门人…

MySQL原理简介—12.MySQL主从同步

大纲 1.异步复制为MySQL搭建一套主从复制架构 2.半同步复制为MySQL搭建一套主从复制架构 3.GTID为MySQL搭建一套主从复制架构 4.并行复制降低主从同步延迟或强制读主库1.异步复制为MySQL搭建一套主从复制架构 (1)MySQL主从复制的原理 (2)搭建主从复制架构的配置(1)MySQL主从复制…

java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)

java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)@目录说明:基础工具类MsgPageResultResponseBusinessDomainEnum(枚举)EsDocumentConstants(常量)本人其他文章链接 说明:基础工具类Msg package com.geespace.microservices.data.computing.model.…

[MYSQL] MYSQL 时间与时区

MYSQL 版本:MYSQL 5.7.38-221001-logMYSQL 时间与时区概述 GMT(格林尼治标准时间、世界时间) 与 UTC(协调世界时间)‌GMT(Greenwich Mean Time,格林威治标准时间)‌:GMT是基于地球自转和对恒星的观测来定义的时间标准,将地球划分为24个时区。它以英国伦敦郊区的格林尼治天文…

51单片机入门:数码管(3)

数码管简介数码管每段其本质就是个LED灯,只需要控制特定的LED灯亮就能显示数据。普中开发版所使用的是两个并在一起共阴极连接的“4位数码管”,可以同时显示8个数字。数码管的显示可以分成静态显示和动态显示,这里先介绍最简单的静态显示。数码管分为共阴极连接和共阳极连接…

使用java在未知表字段情况下通过sql查询信息

使用java在未知表字段情况下通过sql查询信息场景 在只知道表名,不知道表包含哪些字段情况下,查询该表信息的场景 解决方案 @Testpublic void test() {Connection connection;String DB_URL = "jdbc:mysql://192.168.20.75:9950/geespace_bd_platform_dev?characterEnco…

WnRAR将rar后缀格式文件转成zip后缀格式

前言全局说明使用 winRAR 自带的转换功能,可以最大程度的保留原始信息, 比如: 打包时间、CRC32值等一、说明 环境: Windows 11 家庭版 23H2 22631.3737 WinRAR 6.00(32位)二、rar 转 zip 2.12.2 选择要转换的文件 右边可以根据类型筛选2.3 选择要转成的格式 zip2.4 选择转成输…

opensuse系统下QtCreator中文输入法失效解决,亲测有效

首先安装QTCreator,这里不再详细赘述。克隆fcitx-qt5仓库,然后在该目录下新建build文件 克隆命令如下git clone https://gitcode.com/gh_mirrors/fc/fcitx-qt5.git安装cmakezypper install cmake进入到build目录 运行命令cmake ..报错如下 解决办法 运行如下指令 sudo zypper…

数值分析:线性方程组的直接解法(上)

提纲背景介绍 三角方程组 Gauss消去法 附录一、背景介绍 1.1 线性方程组的相关概念 线性方程组在解决现实师姐问题中直接产生,最小二乘数据拟合、微分方程边值问题和初边值问题的数值解产生了大量的线性方程组。 线性方程组系数矩阵的类型分别有稠密型(dense):几乎所有元素都…