『模拟赛』NOIP2024加赛2

Rank

一直烂,什么时候触底反弹(

image

A. 新的阶乘

赛时觉得线筛一遍同时统计每个质数的指数就做完了,然后本机怎么跑不进 1s,卡常卡了半个小时,最后没 T,但是 vector 炸了,70pts。

可以换思路考虑,赛时一直没转换过来。对于每个质数枚举其倍数统计贡献。复杂度不知道多少,跑得中等速度。

点击查看代码
#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 pii pair<int, int>
#define pll pair<ll, ll>
#define fi first
#define se second
#define M_P(x, y) make_pair(x, y)
#define P_B(x) push_back(x)
const int Ratio = 0;
const int N = 1e7 + 5;
const int mod = 1e9 + 7;
int n;
int pri[N], tot;
bool yz[N];
namespace Wisadel
{inline short main(){freopen("factorial.in", "r", stdin), freopen("factorial.out", "w", stdout);n = qr;printf("f(%d)=", n);fo(i, 2, n){if(!yz[i]) pri[++tot] = i;fo(j, 1, tot){if(i * pri[j] > n) break;yz[i * pri[j]] = 1;if(i % pri[j] == 0) break;}}bool ss = 1;fo(i, 1, tot){if(!ss) putchar('*');ss = 0;ll num = 0;for(int j = pri[i]; j <= n; j += pri[i]){int zc = j, cz = 0;while(zc % pri[i] == 0) zc /= pri[i], cz++;num += 1ll * cz * (n - j + 1);}if(num == 1) printf("%d", pri[i]);else printf("%d^%lld", pri[i], num);}putchar('\n');return Ratio;}
}
signed main(){return Wisadel::main();}

B. 博弈树

上来猜出结论和直径有关,但是忘了怎么打,打了巨大长时间,然后判断条件写错了挂 40pts。

从必胜开始倒着推。考虑若移动前在直径的一端,那么移动直径后后手无法移动,即此时先手必胜。考虑在距直径一端距离为 1 时,只需移动直径减二的长度,那么后手只能移动直径减一的长度到直径一端,先手必胜。以此类推,扩展发现当在直径上存在对称点时必胜,即可以找到一个与当前点不同的、到直径一端距离等于当前点到直径另一端的距离的点时必胜。

正确性:设当前点到直径两端较短距离为 \(x\),那么若此时可移动 \(d-2x\) 长度,那么对手一定最少只能移动 \(d-2x+1\) 长度,此时当前点到直径两端较短距离成为 \(x-1\),可以重复上述操作直到 \(x=0\),走一遍直径结束游戏。

这么一看,显然只有直径长度为偶数(边)时的中点无法先手必胜。

考虑如何做。赛时选了一种比较麻烦的判断方法:先 dfs 一遍,找到直径的两个端点,然后分别以两个端点为根做 dfs 并记录深度,后手必胜判断条件为 \(dis_1+dis_2=d\)\(dis_1=dis_2\)

点击查看代码
#include<bits/stdc++.h>
#define fo(x, y, z) for(register 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 pii pair<int, int>
#define pll pair<ll, ll>
#define fi first
#define se second
#define M_P(x, y) make_pair(x, y)
#define P_B(x) push_back(x)
const int Ratio = 0;
const int N = 1e5 + 5;
const int mod = 1e9 + 7;
int n, m, r1, r2;
int dp[3][N], ans;
pii mdl[N], mdr[N];
int hh[N], to[N << 1], ne[N << 1], cnt;
namespace Wisadel
{void Wadd(int u, int v){to[++cnt] = v;ne[cnt] = hh[u];hh[u] = cnt;}void Wdfs(int u, int fa){mdl[u] = M_P(0, 0);mdr[u] = M_P(0, 0);for(int i = hh[u]; i != -1; i = ne[i]){int v = to[i];if(v == fa) continue;Wdfs(v, u);if(!mdl[v].fi){if(!mdl[u].fi) mdl[u].fi = 1, mdl[u].se = v;else if(!mdr[u].fi) mdr[u].fi = 1, mdr[u].se = v;}else if(mdl[v].fi + 1 > mdl[u].fi) mdr[u] = mdl[u], mdl[u].fi = mdl[v].fi + 1, mdl[u].se = mdl[v].se;else if(mdl[v].fi + 1 > mdr[u].fi) mdr[u].fi = mdl[v].fi + 1, mdr[u].se = mdl[v].se;}if(mdl[u].fi + mdr[u].fi > ans){r1 = mdl[u].se, r2 = mdr[u].se;ans = mdl[u].fi + mdr[u].fi;}}void Wser(int u, int fa, int id){dp[id][u] = dp[id][fa] + 1;for(int i = hh[u]; i != -1; i = ne[i]){int v = to[i];if(v == fa) continue;Wser(v, u, id);}}inline short main(){freopen("tree.in", "r", stdin), freopen("tree.out", "w", stdout);n = qr, m = qr;memset(hh, -1, sizeof hh);fo(i, 1, n - 1){int a = qr, b = qr;Wadd(a, b), Wadd(b, a);}Wdfs(1, 0);dp[1][0] = dp[2][0] = -1;if(!r2) r2 = 1;Wser(r1, 0, 1); Wser(r2, 0, 2);fo(i, 1, m){int a = qr;if(dp[1][a] == dp[2][a] && dp[1][a] + dp[2][a] == ans) puts("Bob");else puts("Alice");}return Ratio;}
}
signed main(){return Wisadel::main();}

C. 划分

结论题。赛时想到结论没想到怎么实现,鉴定为 hash 彩笔。

首先发现在最高位为 1 的情况下位数越多越优。考虑什么时候存在无用的位数,发现数据含有一个 \(\forall i\in [1,k],s_i=0\) 的特殊点。思考发现当前 \(x\)\(x\gt k-1\))个字符均为 0 时,答案显然可以计数得出 \(\sum_{i=k-1}^{x-1}\ \binom{x-1}{i}\),当然这些 0 还可以作前缀加到后面一坨数上,所以总答案即为 \(\sum_{i = k-1}^x\sum_{j=k-1}^{i-1}\ \binom{i-1}{j}\),化简一下得出原式 \(=\sum_{i=k-1}^{x}\ \binom{x+1}{i+1}\),方法依然是昨天用的杨辉三角,手模一下很快出来。

然后考虑其他情况。此时由于已发现的结论,串一定被划分成 1 个长度为 \(n-k+1\) 的串和 \(k-1\) 个长度为 1 的串。考虑那么问题就转化成了求出值最大的长度为 \(n-k+1\) 的串并记录其数量。比较两个字符串可以用 hash + 二分,注意只用比较前 \(n-k\) 位,因为最后一位无论放在这里还是单拿出来贡献是一样的,然后就做完了。对于情况一复杂度是 \(\mathcal{O(n)}\) 的,情况二大概是 \(\mathcal{O(k\log n+n)}\) 的。

细节 n 多个。首先 \(n=k\) 要特判,不然二分直接似了。然后二分边界问题和取值问题,卡我很久。然后第二个包加了自然溢出的 hack。然后注意一些初始化问题。然后没了。

点击查看代码
#include<bits/stdc++.h>
#define fo(x, y, z) for(register 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;
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 pii pair<int, int>
#define pll pair<ll, ll>
#define fi first
#define se second
#define M_P(x, y) make_pair(x, y)
#define P_B(x) push_back(x)
const int Ratio = 0;
const int N = 2e6 + 5;
const int mod = 998244353;
const int base = 233;
int n, k;
string s;
ll has[N], bas[N];
ll ans, num;
namespace Wtask
{ll jc[N], ny[N];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;}ll Wc(int n, int m){return jc[n] * ny[m] % mod * ny[n - m] % mod;}short main(){jc[0] = ny[0] = 1;fo(i, 1, n) jc[i] = jc[i - 1] *i % mod;ny[n] = Wqp(jc[n], mod - 2);fu(i, n - 1, 1) ny[i] = ny[i + 1] * (i + 1) % mod;int tot = 0;fo(i, 1, n) if(s[i] == '0') tot++;else break;if(tot == n) tot--;ll sum = 0;fo(i, tot + 1, n) sum = (sum * 2 % mod + (s[i] == '1')) % mod;ll num = 0;fo(i, k - 1, tot) num = (num + Wc(tot, i)) % mod;printf("%lld %lld\n", sum, num);return Ratio;}
}
namespace Wisadel
{ll Wgh(int l, int r){return (has[r] - has[l - 1] * bas[r - l + 1] % mod + mod) % mod;}short main(){freopen("divide.in", "r", stdin), freopen("divide.out", "w", stdout);n = qr, k = qr;cin >> s;s = " " + s;if(n == k){ll zc = 0;fo(i, 1, n) zc += s[i] == '1';printf("%lld %d\n", zc, 1);return Ratio;}bool task = 1;fo(i, 1, k - 1) if(s[i] != '0'){task = 0; break;}if(task) return Wtask::main();bas[0] = 1;fo(i, 1, n) bas[i] = bas[i - 1] * base % mod;fo(i, 1, n) has[i] = (has[i - 1] * base % mod + (s[i] == '1')) % mod;int nl = 1;int num = 1;fo(i, 2, k){int l = 0, r = n - k;while(l < r){// 匹配位数int mid = ((l + r + 1) >> 1);if(Wgh(nl, nl + mid - 1) == Wgh(i, i + mid - 1)) l = mid;else r = mid - 1;}if(l == n - k) num++;else if(s[nl + l] < s[i + l]) nl = i, num = 1;}ll zc = 0;fo(i, nl, nl + n - k) zc = (zc * 2 % mod + (s[i] == '1')) % mod;fo(i, 1, n) if(i < nl || i > nl + n - k) zc = (zc + (s[i] == '1')) % mod;printf("%lld %d\n", zc, num);return Ratio;}
}
signed main(){return Wisadel::main();}

D. 灯笼

原题 [EGOI2021] Lanterns / 灯笼 。

赛时一点不会打,想不到什么好的转移方式就没写。

神仙 dp,感觉状态设计就不是一般人能想到的。先从暴力说起,设 \(f_{l,r,i}\) 为当前灯火范围为 \([l,r]\) 且位于 \(i\) 段山峰走完全程的最小代价,那么转移时需要满足当前可以从 \(i\) 走到 \(j\)。复杂度大概是 \(\mathcal{O(n^4)}\)

首先状态三维就很过不去,我们需要将其压到至多两维。考虑改设 \(f_{x,y}\) 表示第 \(x\) 盏灯提供最小灯火值,\(y\) 盏灯提供最大灯火值,且满足 \([a_x,b_y]\) 的灯火值都被提供,经过所有位置的最小值。这样设计既可以得到当前可经过的区间,也能得到当前所在区间,非常神的设计。

我们需要提前处理出购买第 \(i\) 盏灯后可经过的山峰区间,使得在得到 \(x,y\) 后可以通过取交集来得出当前可经过山峰区间。预处理是 \(\mathcal{(?,n^2]}\) 的,比较好写。

然后是难点转移。发现如果暴力枚举灯还是 \(\mathcal{O(n^3)}\) 的,过不去。怎么优化?假设当前需要向右走,左端点先不动,当遇到一个不合法的转移时(当前山峰区间 \([L,R]\) 无法不包含 \(p_i\),或 \([a_i,b_i]\)\([a_x,b_x]\) 无交集),对于更小的右端点,该转移依然无法进行。出现了单调性,我们可以直接分别按左端点升序、右端点降序排序,然后上堆优化转移,这样复杂度就被降到 \(\mathcal{O(n^2\log n)}\) 级别的了,可行。

边界上,当 \(a_x=1\)\(b_y=n\) 时表示已经走完了,所以有 \(f_{x,y}=0\),其余由于是求最小值,赋成极大值即可。当遇到 \(a_x\gt a_y\)\(b_x\gt b_y\) 时,此时比较显然我们可以直接将 \(f_{y,y}/f_{x,x}\) 的值赋给 \(f_{x,y}\) 即可。

点击查看代码
#include<bits/stdc++.h>
#define fo(x, y, z) for(register 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;
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 pii pair<int, int>
#define pll pair<ll, ll>
#define fi first
#define se second
#define M_P(x, y) make_pair(x, y)
#define P_B(x) push_back(x)
const int Ratio = 0;
const int N = 2e3 + 5;
const int mod = 998244353;
int n, k;
int h[N], p[N], c[N], a[N], b[N];
pii uc[N], dc[N]; // 上下界可达区间 : upcan, downcan
int idl[N], idr[N]; // 按左/右边界排序后下标
int f[N][N];
priority_queue<pii, vector<pii>, greater<pii> > Ql[N], Qr[N];
namespace Wisadel
{void Wsolvel(int l, int r, int L, int R){while(Ql[l].size() && (p[Ql[l].top().se] < L || p[Ql[l].top().se] > R || a[Ql[l].top().se] > b[r] || a[l] > b[Ql[l].top().se]))Ql[l].pop();if(Ql[l].size()) f[l][r] = min(f[l][r], Ql[l].top().fi);}void Wsolver(int l, int r, int L, int R){while(Qr[r].size() && (p[Qr[r].top().se] < L || p[Qr[r].top().se] > R || a[Qr[r].top().se] > b[r] || a[l] > b[Qr[r].top().se]))Qr[r].pop();if(Qr[r].size()) f[l][r] = min(f[l][r], Qr[r].top().fi);}short main(){freopen("lantern.in", "r", stdin), freopen("lantern.out", "w", stdout);n = qr, k = qr;fo(i, 1, n) h[i] = qr;fo(i, 1, k) p[i] = qr, c[i] = qr, a[i] = qr, b[i] = qr;fo(i, 1, k){uc[i] = dc[i] = M_P(p[i] + 1, p[i] - 1);while(uc[i].fi > 1 && h[uc[i].fi - 1] <= b[i]) uc[i].fi--;while(uc[i].se < n && h[uc[i].se + 1] <= b[i]) uc[i].se++;while(dc[i].fi > 1 && h[dc[i].fi - 1] >= a[i]) dc[i].fi--;while(dc[i].se < n && h[dc[i].se + 1] >= a[i]) dc[i].se++;}fo(i, 1, k) idl[i] = idr[i] = i;sort(idl + 1, idl + 1 + k, [](int x, int y){return a[x] < a[y];});sort(idr + 1, idr + 1 + k, [](int x, int y){return b[x] > b[y];});fo(i, 1, k) fo(j, 1, k){int l = idl[i], r = idr[j];f[l][r] = 2e9;int L = max(dc[l].fi, uc[r].fi), R = min(dc[l].se, uc[r].se);if(p[l] < L || p[l] > R || p[r] < L || p[r] > R || (a[l] > a[r] && b[l] > b[r])) continue;// 出生点不符合要求                                  不满足定义if(a[l] == 1 && b[r] == n) f[l][r] = 0; // 到头了else if(a[l] > a[r]) f[l][r] = f[r][r];else if(b[l] > b[r]) f[l][r] = f[l][l]; // 直接转移else{Wsolvel(l, r, L, R);Wsolver(l, r, L, R);}if(f[l][r] < 2e9){Ql[l].push(M_P(f[l][r] + c[r], r));Qr[r].push(M_P(f[l][r] + c[l], l));}}fo(i, 1, k) printf("%d\n", (f[i][i] >= 2e9) ? -1 : f[i][i] + c[i]);return Ratio;}
}
signed main(){return Wisadel::main();}

还是烂,不过打得烂确实能暴露出自己的很多问题:想不到正解,想到错解后不愿再优化改进等。这一场就是这样,T1 感觉上就假的做法硬卡了半小时常,T2 T3 的结论都想到了,但是就是有细节问题。

字符串和 dp 还是太不熟了,得加练,但真的还有时间吗?抓好每一道模拟赛题,尽量提升吧。

还有就是达到最后无论如何不能摆烂,T4 暴力不会抓紧回看前面,已经出现不止两次因为回看太晚导致发现错却来不及改的痛苦情况了。


完结撒花~

😦,打一场少一场了

image

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

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

相关文章

矩阵求导 d(A*X)/dX

矩阵求导 d(A*X)/dX简单矩阵求导 $\frac{ \part (A \times X) }{ \part X }=A$。证明如下,自行体会。 感谢 https://www.cnblogs.com/sunny99/ sumoier对本文的帮助

学习笔记(二十六):资源分类与访问(Resources)

概述: 应用开发中使用的各类资源文件,需要放入特定子目录中存储管理。 资源目录的示例如下所示, base目录、限定词目录、rawfile目录、resfile目录称为资源目录;element、media、profile称为资源组目录。resources |---base | |---element | | |---string.json | |…

java微服务的异常

1.依赖异常须知: 【 如果项目的结构是单个模块的,需要给每个单个模块添加起步依赖 spring-boot-starter-parent,指定版本 】 【 如果项目的结构是子父模块的,只需要给父模块添加起步依赖 spring-boot-starter-parent,指定版本,所有子模块引入父模块就行 】配置文件你指定…

C# WebSocket的简单使用【使用Fleck实现】

有bug,不推荐使用 有bug,不推荐使用 有bug,不推荐使用2.WebSocketHelper 新建 WebSocketHelper.csusing Fleck;namespace WebSocket {internal class WebSocketHelper{//客户端url以及其对应的Socket对象字典IDictionary<string, IWebSocketConnection> dic_Sockets =…

第三十五讲:为什么临时表可以重名?

创建临时表,一部分为了优化查询,join在临时表里查询出结果后导入到正常表中,他也支持多session的查询优化,更重要一点是在session会话关闭后,临时表会自动销毁。嗯就这样 另外分清他和内存表的区别 内存表一定是从memory引擎创建的,临时表可以由memory引擎创建第三十五讲…

如何理解shell命令 cd $(dirname $0)

如何理解shell命令 cd $(dirname $0)-CSDN博客

对C++程序使用输入输出重定向

一般来说,在Visual Studio使用文件重定向有三种方法: 方法一:通过命令行参数实现 项目→属性→配置属性→调试→命令参数然后就在这里加上你的命令行参数 比如我有这样一段程序: #include <iostream> #include <fstream> #include "Sales_item.h"int…

红米k70怎么设置「短信通知」在锁屏时隐藏内容,不锁屏时不隐藏内容

红米 K70 设置短信通知在锁屏时隐藏内容、不锁屏时不隐藏内容,可以按照以下步骤进行操作:打开手机设置:在主屏幕上找到并点击 “设置” 图标,进入手机设置页面。 进入通知与控制中心:在设置页面中,找到并点击 “通知与控制中心” 选项。 选择锁屏通知:在通知与控制中心页…

c语言中声明数组时, 元素个数必须使用常量表达式

001、[root@PC1 test]# ls test.c [root@PC1 test]# cat test.c ## 测试程序 #include <stdio.h>int main(void) {int var1 = 5; // 初始化一个变量var1int array1[var1] = {3,5,8,4,9}; // 初始化数组return 0; } [root@PC1 test]# gcc test.c …

图的基本操作

目录1.图2.图的结构体定义3.图的初始化4.添加顶点、删除顶点4.1添加顶点4.2删除顶点5.添加边、删除边5.1添加边5.2删除边6.打印图7.main函数 在生命旅途中,我们就像是一个个节点,被无数看不见的边相连。每一次的相识与相离,都在这张巨大的网络图中留下独特的印记。 1.图 图(…

正态分布

正态分布 1 标准正态分布 1.1概率密度函数 \[f(x) = \frac{1}{\sqrt{2\pi}}e^{-\frac{x^2}{2}} \]1.2 累计分布函数 \[F(x) = \frac{1}{\sqrt{2\pi}} \int_{-\infty}^{x}e^{-\frac{t^2}{2}}dt \] 2 (一般)正态分布 2.1 概率密度函数 \[f(x) = \frac{1}{\sqrt{2\pi\sigma…

Pycharm中使用AI辅助Coding工具Aws Toolkit

一、安装插件 二、重启完了以后点击左下角的aws 三、点developer tools,双击codewhisperer中的start,点击connect 四、点击sign out,open and copy code五、跳转到网页浏览器中打开登录界面,我们在图中所示的 code 一栏中粘贴上验证码,点击"next"按钮六、没有账…