『模拟赛』多校A层冲刺NOIP2024模拟赛17(更新 T2 T4)

Rank

一般

image

image

A. 网络

签不上的签到题。

首先考虑枚举路径的做法,如果先枚举再计算的话复杂度会是 \(\mathcal{O(\binom{n+m-2}{n-1}(n+m))}\) 的,稍微优化一点的过程中可以去掉后面的 \((n+m)\)。考虑此时我们要记什么,首先遇到加号其前面的值 \(z\) 就确定了,若上个符号为乘号那么需记录乘数 \(x\),同时显然还需记录当前的数 \(y\),可以得到 30pts。

迁移到 \(\mathcal{O(nm)}\) 的做法上,稍微改变一些定义,将记当前的数直接改为记当前的数与所记乘数的积。分讨三种转移:

  • 若当前位置为数字:\(y\leftarrow 10x+x\cdot a_{i,j}\)
  • 若当前位置为乘号:\(x\leftarrow y,\ y\leftarrow 0\)
  • 若当前位置为加号:\(z\leftarrow y+z,\ y\leftarrow 0,\ x\leftarrow 1\)

发现这样转移仍然是针对一个表达式的,优化也很简单,提前处理可能的 \(x\) 值,即到这个点一共有几种可能。感性理解就是:在这个点一共会进行棘刺这样的转移。然后就做完了,复杂度 \(\mathcal{O(nm)}\)

点击查看代码
#include<bits/stdc++.h>
#define fo(x, y, z) for(register int (x) = (y); (x) <= (z); (x)++)
#define fu(x, y, z) for(register int (x) = (y); (x) >= (z); (x)--)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#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 = 2000 + 5;
const int mod = 998244353;
int n, m;
string s[N];
ll z[N][N], x[N][N], y[N][N], zc[N][N];
namespace Wisadel
{short main(){freopen("grid.in", "r", stdin), freopen("grid.out", "w", stdout);n = qr, m = qr;fo(i, 1, n) cin >> s[i], s[i] = " " + s[i];zc[1][0] = 1;x[1][0] = 1;fo(i, 1, n) fo(j, 1, m){x[i][j] = (x[i - 1][j] + x[i][j - 1]) % mod;y[i][j] = (y[i - 1][j] + y[i][j - 1]) % mod;z[i][j] = (z[i - 1][j] + z[i][j - 1]) % mod;zc[i][j] = (zc[i - 1][j] + zc[i][j - 1]) % mod;if(s[i][j] == '+'){z[i][j] = (z[i][j] + y[i][j]) % mod;x[i][j] = zc[i][j];y[i][j] = 0;}else if(s[i][j] == '*'){x[i][j] = y[i][j];y[i][j] = 0;}else y[i][j] = (y[i][j] * 10 % mod + (s[i][j] - '0') * x[i][j] % mod) % mod;}printf("%lld\n", (z[n][m] + y[n][m]) % mod);return Ratio;}
}
signed main(){return Wisadel::main();}

B. 矩形

正解是根号分治。不是很会,于是在 GGrun 的帮助下焯过去了。

思路很平凡,将同一列和同一行的点通过排序处理出来,然后看列数和行数哪个少用哪个。求答案时朴素实现是枚举两列,双指针移动找匹配段,记录总数 \(x\),贡献为 \(\frac{x(x-1)}{2}\),统计答案即可。

发现会 TLE,于是考虑少些无用的枚举。我们只枚举一列,然后枚举列上面的每个点,再枚举该点所在行上的点,更新这些点所在列的贡献。发现 \(\frac{x(x-1)}{2}\) 可以拆成 \(\frac{x^2}{2}-\frac{x}{2}\),根据转移式 \((x+1)^2=x^2+2x+1\) 可以递推出总贡献,最后再枚举列统计贡献即可,然后就过了,复杂度 \(\mathcal{O(能过)}\)(我的实现常数过大会被卡

焯代码
#include<bits/stdc++.h>
#define fo(x, y, z) for(register int (x) = (y); (x) <= (z); (x)++)
#define fu(x, y, z) for(register int (x) = (y); (x) >= (z); (x)--)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#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;
const int mod = 998244353;
int n, tot;
int prex[N], prey[N];
ll sum[N], ans, ans1[N], ans2[N];
struct rmm
{int x, y;bool operator < (const rmm &A) const{return y == A.y ? x < A.x : y < A.y;}
} d[N], p[N];
pii xx[N], yy[N];
namespace Wisadel
{bool cmpn(rmm A, rmm B){return A.x == B.x ? A.y < B.y : A.x < B.x;}bool cmpm(rmm A, rmm B){return A.y == B.y ? A.x < B.x : A.y < B.y;}short main(){freopen("rect.in", "r", stdin), freopen("rect.out", "w", stdout);n = qr;ll c = 1;fo(i, 2, n) sum[i] = sum[i - 1] + c, c++;fo(i, 1, n) d[i].x = p[i].x = qr, d[i].y = p[i].y = qr;sort(d + 1, d + 1 + n, cmpn);sort(p + 1, p + 1 + n, cmpm);int zoz = 0;fo(i, 1, n) if(d[i].x != d[i - 1].x) xx[++tot].fi = d[i].x, xx[tot].se = i, prex[d[i].x] = tot;fo(i, 1, n) if(p[i].y != p[i - 1].y) yy[++zoz].fi = p[i].y, yy[zoz].se = i, prey[p[i].y] = zoz;if(zoz < tot){swap(tot, zoz);fo(i, 1, max(tot, zoz)) swap(xx[i], yy[i]);fo(i, 1, n) swap(d[i].x, p[i].y), swap(d[i].y, p[i].x), swap(prex[i], prey[i]);}xx[tot + 1].se = n + 1;yy[zoz + 1].se = n + 1;fo(i, 1, tot){int z1 = xx[i].se;while(z1 <= xx[i + 1].se - 1){int z2 = lower_bound(p + 1, p + 1 + n, (rmm){d[z1].x, d[z1].y}) - p;int bz = prey[p[z2].y]; z2++;while(z2 <= yy[bz + 1].se - 1){ans1[prex[p[z2].x]] += ans2[prex[p[z2].x]] * 2 + 1, ans2[prex[p[z2].x]]++;z2++;}z1++;}fo(j, i + 1, tot)ans += (ans1[j] - ans2[j]) / 2, ans1[j] = ans2[j] = 0;}printf("%lld\n", ans);return Ratio;}
}
signed main(){return Wisadel::main();}

正解晚上补。

发现根号分治实现也很简单啊。首先还是把点都按列存起来,记录每列的点数。对于点数不大于 \(\sqrt{n}\) 的列,把它上面的所有点按行存起来,然后逐行处理,到每个点暴力跑统计出到每一行的二元组数量,统计答案后记得清除。复杂度 \(\mathcal{O(n\sqrt{n})}\)

对于点数超过 \(\sqrt{n}\) 的列,更暴力了,直接 \(\mathcal{O(n)}\) 看每个点的贡献,最后统计答案即可,注意不要重复统计。复杂度 \(\mathcal{O(\frac{n^2}{\sqrt{n}})=O(n\sqrt{n})}\)

因此复杂度是 \(\mathcal{O(n\sqrt{n})}\) 的,不愧是正解,跑得很快。

正解代码
#include<bits/stdc++.h>
#define fo(x, y, z) for(register int (x) = (y); (x) <= (z); (x)++)
#define fu(x, y, z) for(register int (x) = (y); (x) >= (z); (x)--)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#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;
const int mod = 998244353;
int n, len;
int cnt[N];
ll ans, now[N];
struct rmm{int x, y;} d[N];
vector<int> vx[N], vy[N];
bool yz[N];
namespace Wisadel
{void Wsolsmall(){fo(i, 1, n) if(cnt[d[i].x] <= len) vy[d[i].y].P_B(d[i].x);fo(i, 1, n) sort(vx[i].begin(), vx[i].end(), greater<int>());fo(j, 1, n){for(int i : vy[j]){vx[i].pop_back();for(int k : vx[i]) now[k]++;}for(int i : vy[j]) for(int k : vx[i])ans += now[k] * (now[k] - 1) / 2, now[k] = 0;}}void Wsolbig(){fo(i, 1, n){if(cnt[i] <= len) continue;fill(yz + 1, yz + 1 + n, 0);fill(now + 1, now + 1 + n, 0);for(int j : vx[i]) yz[j] = 1;fo(ii, 1, n) if(yz[d[ii].y]) now[d[ii].x]++;fo(ii, 1, n) if(cnt[ii] <= len || ii < i)ans += now[ii] * (now[ii] - 1) / 2;}}short main(){freopen("rect.in", "r", stdin), freopen("rect.out", "w", stdout);n = qr; len = sqrt(n);fo(i, 1, n) d[i].x = qr, d[i].y = qr, cnt[d[i].x]++, vx[d[i].x].P_B(d[i].y);Wsolsmall();Wsolbig();printf("%lld\n", ans);return Ratio;}
}
signed main(){return Wisadel::main();}

C. 集合

容斥 + FFT,男蚌。

赛时猜了个结论拿了 10pts。

D. 倒水

期望 + 线段树优化,牛魔。

赛时打了个暴力拿了 24pts。

44pts 做法:期望转概率。设 \(f_{i,j}\) 表示第 \(i\) 个杯子倒水时有 \(k\) 个水的概率。发现当一个杯子往前倒水时之后一定没有操作了,因此对于枚举到的每个杯子分两种情况考虑,一是往前倒水,然后直接统计答案;二是向后转移,只统计自身的答案。转移非常好写:

\[ans=\sum p_i\times v_i \]

\[f_{k,\min(j,a_k)}=\sum_{i\lt k}\ p_i \]

其中 \(p_i=\frac{f_{i,j}}{n-1}\)。复杂度 \(\mathcal{O(n^3)}\)。前缀优化可以达到 \(\mathcal{O(n^2)}\),可以得到 60pts。

点击查看代码
#include<bits/stdc++.h>
#define fo(x, y, z) for(register int (x) = (y); (x) <= (z); (x)++)
#define fu(x, y, z) for(register int (x) = (y); (x) >= (z); (x)--)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#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 = 2000 + 5;
const int mod = 998244353;
int n;
int a[N];
ll f[N][N], ans[N];
namespace Wisadel
{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;}short main(){freopen("bottle.in", "r", stdin), freopen("bottle.out", "w", stdout);n = qr;fo(i, 1, n) a[i] = qr;ll ny = Wqp(n - 1, mod - 2);f[1][a[1]] = 1;fo(i, 1, n) fo(j, 1, a[i]){ll p = f[i][j] * ny % mod;fo(k, 1, i - 1){int v = min(j, a[k]);ans[i] = (ans[i] + p * (j - v) % mod) % mod;ans[k] = (ans[k] + p * v) % mod;}fo(k, i + 1, n){int v = min(j, a[k]);ans[i] = (ans[i] + p * (j - v) % mod) % mod;f[k][v] = (f[k][v] + p) % mod;}}fo(i, 1, n) printf("%lld\n", ans[i]);return Ratio;}
}
signed main(){return Wisadel::main();}

比昨天强点,但不多。

开题一眼三道取模压迫感就来了,因为 T1 看了会不会打就先通读了一遍,然后打 T4,打完打的 T2,结果空间没改 + 取模没改直接嗯挂 52pts。

T1 最后 15min 想到了过程中计算,少了个很大的常数但没有多得分,其实感觉到这再想想就能做出来了,可惜回看得太晚来不及了。

突然想到一场比赛三道 dp,两道计数(


完结撒花~

www 怎么状态越来越差了(

image

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

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

相关文章

Unleashing Reasoning Capability of LLMs via Scalable Question Synthesis from Scratch

1. 概述 LLM的SFT数据合成工作不可避免的可以划分为多个阶段:指令合成 响应合成 数据筛选。本篇文章采用了传统LLM的训练过程(SFT+DPO)进行数据合成。在领域专有模型(DeepSeekMath7B-RL,Qwen2-Math-7BInstruct)的基础上,指令合成:通过QFT(即SFT)使得模型能够正确的生…

【Azure Developer】VS Code打包Java maven Project 遇见 BUILD FAILURE

问题描述 在VS Code中创建的Java Maven项目,在进行项目打包时,遇见 BUILD FAILURE\lbimage> mvn -clean package [INFO] Scanning for projects... [INFO] [INFO] ----------------< org.yourcompany.yourproject:lbimage >----------------- [INFO] Building lbima…

项目经理在项目初期应如何界定项目范围

在项目初期,项目经理应该明确项目范围以确保成功。这包括确定项目目标、明确项目结果、识别主要利益相关者、进行需求收集、创建详细的工作分解结构(WBS)。其中,创建详细的工作分解结构是至关重要的步骤。WBS 将项目活动细分为可管理的任务,确保每个项目组件都得到适当的关…

[CSP-S 2024] 超速检测

前言 寄! 算法 计算超速区间 容易发现可以计算出每一辆车的超速区间 分讨策略大致如下void Calc(int Now) {if (Car[Now].v > V){if (Car[Now].a >= 0){Car[Now].Left = Car[Now].d, Car[Now].Right = L;return;}else{Car[Now].Left = Car[Now].d;Car[Now].Right = (int)…

ctfshow web入门 文件上传

Ctfshow Web入门 151查看源代码,发现只能上传.png的文件 用bp抓包.png的图片格式 添加一句话木马,文件格式修改成.php对于上传成功的后门代码, 直接通过hackbar发送post包利用php内置system()函数执行查看flag.php文件152 和上一题做题步骤一样但此题考点不同的是添加了后端…

什么是软件即服务(SaaS)

软件即服务(SaaS)作为一种基于云计算的软件交付模式,具有多租户架构、网络访问、定制化和灵活性、安全性和可靠性等特点。它在商业和个人生活中都有广泛的应用,帮助企业降低成本、提高效率和灵活性,同时为个人用户提供便捷和定制化的应用体验。一、软件即服务(SaaS)的定…

如何学习 C 语言

# 如何学习 C 语言 在探索如何学习 C 语言的旅程中,关键步骤包括理解语言基础、实践编程技巧、熟悉标准库、掌握数据结构与算法、以及参与项目实战。首先,深入理解C语言的基础是至关重要的,它不仅包括语法规则和基本数据类型,还涉及指针、内存管理等高级概念。实践编程技巧…

Python 迭代器和生成器的区别

Python 迭代器和生成器的区别:1.迭代器的定义与创;2.生成器的定义与创建;3.迭代器和生成器的使用场景;4.性能对比。通过比较和对比,本文旨在提供一个全面的视角,帮助读者理解何时使用迭代器和生成器,以及如何有效地在Python编程中利用这两种工具。1.迭代器的定义与创建 …

线上服务正常运行一段时间后就开始出现STW超过1秒的young gc是怎么回事

线上服务在一段正常运行后出现STW(Stop-The-World)超过1秒的young gc(垃圾收集)问题可能涉及多个方面的原因:一、内存分配与管理策略;二、GC算法与配置;三、对象生命周期管理;四、系统资源与环境;五、代码质量与优化。在这些方面中,Java虚拟机的内存管理和垃圾收集策…

WPS Excel中配置下拉多选(VBA)

网上找到两种方案,一种利用数据选择其他单元格,也就是在其他单元格建数据。需求是模板,不合适 这里我用的VBA,踩了挺多坑,详细说下 首先更新WPS为最新版,确保可用VBA和JSA  确定使用VBA还是JSA,两种语法不同VBA较老,语法可靠些,推荐(本文使用VBA)JSA为新引入JS,但…

manim边做边学--通用三维坐标系

ThreeDAxes是Manim中用于创建三维坐标系的类。 在数学、物理和工程等领域,三维坐标系的绘制是非常重要的。 ThreeDAxes使得用户能够在动画中直观地展示三维空间中的对象和关系,从而提高演示文稿和教学的效果。 ThreeDAxes提供了多种参数,如坐标轴的范围、长度、颜色、粗细等…

KubeSphere v4 应用商店配置指南

在 KubeSphere v4 版本中,为保持平台的简洁性,系统默认移除了内置应用商店中的应用。用户可以按照下列步骤进行手动配置和添加。注意:应用商店和扩展市场有所不同,扩展市场的使用方法将在后续文档中详细介绍。Helm Repo 源:安装过程中需要从源下载 Chart 包,确保源可用并…