『模拟赛』多校A层冲刺NOIP2024模拟赛04

news/2024/10/9 19:03:23
Rank

赤石场。

image

A. 02表示法

签。

若干天前在洛谷随到过,不过当时只看了眼讨论区就走了www 还好本来不是很难。

发现大体上是一个拆分二的幂的问题,从大到小枚举 2 的幂,判断有没有这个幂只用比较大小关系,然后再对指数做一个同样的操作,递归至不大于 2 为止,注意 \(2^1\) 不用输出 (1)

发现数据范围达到了惊人的 \(10^{180}\),不过它约等于 \(2^{598}\),也就是说对这做法没有影响,只是二的幂要用高精的形式体现。只用到了高精比较,高精乘低精和高精减三个操作,不是很难写。

点击查看代码
#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;
#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 fi first
#define se second
const int Ratio = 0;
const int N = 2e5 + 5;
const int mod = 1e9 + 7;
int pf[N], tot;
int s[600][200], a[200], zc[200];
string op, ss;
namespace Wisadel
{bool Wcmp(int a[], int b[]){if(a[0] != b[0]) return a[0] > b[0];fu(i, a[0], 1) if(a[i] != b[i]) return a[i] > b[i];return 1;}void Wp(int id, int b){fo(i, 0, s[id][0]) a[i] = s[id][i];memset(zc, 0, sizeof zc);int x = 0, len = a[0];fo(i, 1, len){zc[i] = a[i] * b + x;x = zc[i] / 10;zc[i] %= 10;}if(x) len++, zc[len] = x;zc[0] = len;fo(i, 0, len) s[id + 1][i] = zc[i];}void Wjian(int id){fo(i, 1, s[id][0]){if(a[i] >= s[id][i]) a[i] -= s[id][i];else a[i + 1]--, a[i] = a[i] + 10 - s[id][i];}while(!a[a[0]]) a[0]--;}void Wpre(){s[0][0] = s[0][1] = 1;fo(i, 1, 598) Wp(i - 1, 2);}string Wdfsc(int x){if(x == 0) return "0";string sss = "";bool tou = 1;fu(i, 12, 0){if(x >= pf[i]){if(tou) tou = 0;else sss += "+";if(i == 1) sss += "2";else sss += "2(" + Wdfsc(i) + ")";x -= pf[i];}}return sss;}void Wdfs(){if(a[0] == 1 && a[1] == 1){ss += "2(0)"; return ;}if(a[0] == 1 && a[1] == 2){ss += "2"; return ;}bool tou = 1;fu(i, 598, 0){if(Wcmp(a, s[i])){if(tou) tou = 0;else ss += "+";if(i == 1) ss += "2";else ss += "2(" + Wdfsc(i) + ")";Wjian(i);}}}short main(){freopen("pow.in", "r", stdin) , freopen("pow.out", "w", stdout);Wpre();cin >> op;a[0] = op.size();fo(i, 1, a[0]) a[i] = (int)op[i - 1] - '0';fo(i, 1, a[0]) zc[i] = a[a[0] - i + 1];fo(i, 1, a[0]) a[i] = zc[i];pf[0] = 1;fo(i, 1, 12) pf[i] = pf[i - 1] * 2;Wdfs();cout << ss << endl;return Ratio;}
}
int main(){return Wisadel::main();}

B. 子串的子串

加强版 P6292

开场听到 5k 的赞叹后思维就被莫队固定住了,想不到什么很优的 add 操作,最后复杂度大概是 \(\mathcal{O(n^2q)}\) 的(?),拿到 70pts。

考虑正解。发现不带修,因此答案不变,我们可以提前处理出来。设 \(ans_{l,r}\) 表示 \(\left[l,r\right]\) 内本质不同子串个数。枚举串长和左端点,用求出每个串的哈希值,开一个 map 记录该串上次出现的左端点 \(las\),此时 \(\left[las,r\right]\) 显然出现了一个重复串,使 \(ans_{las,r}\) 减一。最后从一端开始枚举所有串,根据二维前缀和的求法可知:

\[ans_{l,r}=ans_{l+1,r}+ans_{l,r-1}-ans_{l+1,r-1}+1+ans_{l,r} \]

当然还有个更好理解的思路,如图:

image

相当于是 \(\left[l,r\right]\) 原本的限制,加上串 \(s_{l,r}\) 本身,然后加 \(ans_{l+1,r}\)\(ans_{l,e-1}\) 时将 \(ans_{l+1,r-1}\) 多算了一遍,减去即可。然后就可以 \(\mathcal{O(1)}\) 查询了,总复杂度是 \(\mathcal{O(n^2+q)}\) 的。

int_R 打了 SAM 效率薄纱所有人%%%。

点击查看代码
#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 pii pair<int , int>
#define fi first
#define se second
const int Ratio = 0;
const int N = 3000 + 5;
const int base = 233;
int n, m;
string s;
ull has[N], k[N];
unordered_map<ull, int> mp;
int ans[N][N];
namespace Wisadel
{ull Whash(int l, int r){return has[r] - has[l - 1] * k[r - l + 1];}short main(){freopen("substring.in", "r", stdin) , freopen("substring.out", "w", stdout);n = qr, m = qr;cin >> s; s = " " + s; k[0] = 1;fo(i, 1, n) has[i] = has[i - 1] * base + s[i], k[i] = k[i - 1] * base;fo(len, 1, n){mp.clear();fo(l, 1, n - len + 1){int r = l + len - 1;ull zc = Whash(l, r);ans[mp[zc]][r]--;mp[zc] = l;}}fu(l, n, 1) fo(r, l, n)ans[l][r] += ans[l + 1][r] + ans[l][r - 1] -ans[l + 1][r - 1] + 1;fo(i, 1, m) printf("%d\n", ans[qr][qr]);return Ratio;}
}
int main(){return Wisadel::main();}

C. 魔法咒语

赛时想到了正反建两棵 trie 树但不知道怎么容斥计数于是止步 20pts。

忘了之前的套路,容斥不会就分讨,不重就不用容斥。我们建反向 trie 树时记录每一种字母节点的数量,然后遍历正向 trie 树的节点,考虑怎么计数。遍历其 26 种子节点,如果该节点没有某种字母的子节点,则此时拼接该字母开头的后缀时一定没有重复情况,那么令 \(ans+=cnt_{该字母}\) 即可。

发现当前缀串取到一个完整的串时,一定可以在其后补一个与最后一个字母相同的字母使其为新串,所以记录一下每个字母是否是某一个串的结尾,然后在上述判断为否的时候再进行判断即可。

但是这种计数局限于串可拆分的情况,对于一个单字母组成的串发现它不会被算入,而两个这样的串又显然能构成一个新串,因此输入时对于这种串直接特判即可。复杂度大概是 \(\mathcal{O(正向\ trie\ 树上节点数\times 26)}\) 的。

点击查看代码
#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;
#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 fi first
#define se second
const int Ratio = 0;
const int N = 4e5 + 5;
const int mod = 1e9 + 7;
int n, tot, oto;
string s[N];
int to[N][26], v[26], ot[N][26], yz[26], fla[26];
ll ans;
namespace Wisadel
{void Wins(string s){int now = 0, len = s.size();fo(i, 0, len - 1){int zc = s[i] - 'a';if(!to[now][zc]) to[now][zc] = ++tot;now = to[now][zc];}}void Wsni(string s){int now = 0, len = s.size();fu(i, len - 1, 0){int zc = s[i] - 'a';if(!ot[now][zc]) ot[now][zc] = ++oto, v[zc]++;now = ot[now][zc];}}short main(){freopen("magic.in", "r", stdin) , freopen("magic.out", "w", stdout);n = qr;fo(i, 1, n){cin >> s[i];Wins(s[i]), Wsni(s[i]);yz[s[i][s[i].size() - 1] - 'a'] = 1;if(s[i].size() == 1 && !fla[s[i][0] - 'a']) ans++, fla[s[i][0] - 'a'] = 1;}fo(i, 1, tot) fo(j, 0, 25)if(!to[i][j]) ans += v[j];else if(yz[j]) ans++;printf("%lld\n", ans);return Ratio;}
}
int main(){return Wisadel::main();}

D. 表达式

挺妙的一道题,赛时由于没开 long long 导致没拿到 15pts 暴力分。

这题用到了数据点分治,本来还以为没有题正解会是这玩意。首先对于 Subtask1,直接 \(\mathcal{O(nm)}\) 暴力即可,主要考虑其它的子任务。

发现其它的子任务的共性是模数拆成不互质的形式的个数后非常少也非常小,拆后最大的模数也只有 29,我们完全可以将其拆开分别计算对于不同模数的不同答案。而且加、乘和乘方都是支持取模运算的,那么就有 \(f(x)=f(x\mod p)\)

我们可以直接暴力处理出 \(\left[0,p-1\right]\) 的所有函数值,用线段树维护,主要操作就是一个线段树合并的过程,而这个又非常简单,只用把左子树的函数值代到右子树的函数里求值即可。这样我们就得到了所有对拆开后的模数取模的答案,写出来就是这个:

\[\begin{cases} ans_1\equiv ans\pmod {p_1}\\ans_2\equiv ans\pmod{p_2}\\\vdots ans_n\equiv ans\pmod{p_n} \end{cases} \]

发现就是 crt 的基本形式,然后直接跑就完了。

点击查看代码
#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;
#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 pil pair<int, ll>
#define fi first
#define se second
const int Ratio = 0;
const int N = 2e5 + 5;
namespace Wistask1
{int n, m, mod;pii d[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;}void Wwork(ll x){fo(i, 1, n){if(d[i].fi == 1) x = (x + d[i].se) % mod;else if(d[i].fi == 2) x = x * d[i].se % mod;else x = Wqp(x, d[i].se);}printf("%lld\n", x);}short main(){n = qr, m = qr, mod = qr;fo(i, 1, n){string s; cin >> s;if(s[0] == '+') d[i].fi = 1;else if(s[0] == '*') d[i].fi = 2;else d[i].fi = 3;ll num = 0;fo(j, 1, s.size() - 1) num = num * 10 + s[j] - '0';d[i].se = num;}fo(i, 1, m){int op = qr, x = qr;if(op == 1) Wwork(x);else{string s; cin >> s;if(s[0] == '+') d[x].fi = 1;else if(s[0] == '*') d[x].fi = 2;else d[x].fi = 3;ll num = 0;fo(j, 1, s.size() - 1) num = num * 10 + s[j] - '0';d[x].se = num;}}return Ratio;}
}
namespace Wvictoria
{int n, m, M;int yz[100], tot, pri[26], mod[26], gs;pil d[N];struct rmm{int mod;ll Wqp(ll x, ll y){ll res = 1;while(y){if(y & 1) res = res * x % mod; x = x * x % mod; y >>= 1;}return res;}int f[N << 2][30];#define ls (rt << 1)#define rs (rt << 1 | 1)#define mid ((l + r) >> 1)void Wpushup(int rt){fo(i, 0, mod - 1) f[rt][i] = f[rs][f[ls][i]];}void Wbuild(int rt, int l, int r){if(l == r){fo(i, 0, mod - 1){if(d[l].fi == 1) f[rt][i] = (i + d[l].se) % mod;else if(d[l].fi == 2) f[rt][i] = d[l].se * i % mod;else f[rt][i] = Wqp(i, d[l].se);}return ;}Wbuild(ls, l, mid), Wbuild(rs, mid + 1, r);Wpushup(rt);}void Wupd(int rt, int l, int r, int x, int op, ll v){if(l == r){fo(i, 0, mod - 1){if(op == 1) f[rt][i] = (i + v) % mod;else if(op == 2) f[rt][i] = v * i % mod;else f[rt][i] = Wqp(i, v);}return ;}if(x <= mid) Wupd(ls, l, mid, x, op, v);else Wupd(rs, mid + 1, r, x, op, v);Wpushup(rt);}} t[5];void Wexgcd(int a, int b, int &x, int &y){if(b == 0){x = 1, y = 0; return ;}Wexgcd(b, a % b, x, y);int z = x;x = y, y = z - (a / b) * y;}short main(){n = qr, m = qr, M = qr;fo(i, 2, 99){if(!yz[i]) pri[++tot] = i;fo(j, 1, tot){if(pri[j] * i > 99) break;yz[pri[j] * i] = 1;if(i % pri[j] == 0) break;}}int zc = M;fo(i, 1, tot){bool yw = 0;while(zc % pri[i] == 0){if(!yw) yw = 1, mod[++gs] = pri[i];else mod[gs] *= pri[i];zc /= pri[i];}}fo(i, 1, n){string s; cin >> s;if(s[0] == '+') d[i].fi = 1;else if(s[0] == '*') d[i].fi = 2;else d[i].fi = 3;ll num = 0;fo(i, 1, s.size() - 1) num = num * 10 + s[i] - '0';d[i].se = num;}fo(i, 1, gs){t[i].mod = mod[i];t[i].Wbuild(1, 1, n);}fo(i, 1, m){int op = qr, x = qr;if(op == 1){ll ans = 0;fo(j, 1, gs){int w = t[j].f[1][x % mod[j]];int md1 = M / mod[j], inv, y;Wexgcd(md1, mod[j], inv, y);ans = (ans + 1ll * w * md1 % M * (inv + mod[j]) % M) % M;}printf("%lld\n", ans);}else{string s; cin >> s;ll zc = 0, num = 0;if(s[0] == '+') zc = 1;else if(s[0] == '*') zc = 2;else zc = 3;fo(j, 1, s.size() - 1) num = num * 10 + s[j] - '0';fo(j, 1, gs) t[j].Wupd(1, 1, n, x, zc, num);}}return Ratio;}
}
namespace Wisadel
{short main(){freopen("expr.in", "r", stdin) , freopen("expr.out", "w", stdout);int u = qr;if(u <= 3) return Wistask1::main();return Wvictoria::main();return Ratio;}
}
int main(){return Wisadel::main();}

别的先不说了,补眼睛鼻托去了。。。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

实现一个烟花效果

1. 首先创建一个烟花类,有烟花上升的效果,烟花爆炸的两种效果(爆炸型和球型)2. 创建线的属性方法,因为上升效果和爆炸效果都会用到3. 上升效果为了达到那种螺旋上升的效果可以通过sin函数实现一个点的偏移量4. 爆炸效果则是将随机生成多条半径不同的线5. 球形效果则是将规…

【Java】反射

Java中的反射机制 动态代理反射 允许对封装类的字段,方法和构造函数的信息进行编程访问 ==》 反射允许对成员变量,成员方法和构造方法的信息进行编程访问 基本操作:获取(获取class对象【字节码对象】) + 解剖 成员变量 Field —— 修饰符、名字、类型、赋值 构造方法 Cons…

DNShell

DNShell 一款基于DNS C2隧道的反弹shell工具。 支持 功能: 支持DNS-recordA-直连型 的C2隧道。 目标: Windows下基于Powershell的反弹。 Linux下基于ShellScript的反弹。 使用方法

【Redis】Redis学习笔记

概况 redis == remote Dictionary Server (远程字典服务) 基于内存的KV键值对内存数据库 作用:分布式缓存,与MySQL共同配合Redis -- 内存 MySQL -- 磁盘Redis -- NoSQL MySQL -- SQL内存存储 和 持久化(RDB+AOF)Redis支持一部将内存中的数据写入硬盘宕机 -- 可自行恢复高…

基于禁忌搜索算法的VRP问题求解matlab仿真,带GUI界面,可设置参数

1.程序功能描述基于禁忌搜索算法的VRP问题求解matlab仿真,带GUI界面,可设置参数。 2.测试软件版本以及运行结果展示MATLAB2022a版本运行 3.核心程序while COUNT<=Itertions ֲ L = zeros(Ant_Num,1); for i=1:Ant_Num Infor_Tabu_tmps = Infor_Tabu(i,:); R = Inf…

CMake 属性之全局属性

CMake 的全局属性是指在 CMake 配置过程中,对整个项目范围生效的设置。这些属性不同于目标 ( Target ) 属性或目录 ( Directory ) 属性,后者仅对特定的目标或目录生效。【写在前面】 CMake 的全局属性是指在 CMake 配置过程中,对整个项目范围生效的设置。 这些属性不同于目标…

自然人信息社工

人,是网络安全全流程中最大的弱点。针对人的攻击往往有出奇不意的效果。而想要利用人的弱点进行攻击,那么对目标的信息收集与了解就是非常重要的了。这篇文章记录了一些常用的用于对人进行身份信息收集的技术。这些技术常被用于溯源取证、社工攻击。 0x00 社工分析中的身份信…

Linux软中断ksoftirqd

前言 在上一篇 LINUX软中断-softirq的描述中,提到过ksoftirqd,这篇文章就介绍ksoftirqd ksoftirqd 是什么? ksoftirqd 是个内核线程,在创建的时候是绑定cpu的,每一个core对应生成一个ksoftirqd 线程 比如当前系统有4个core ~# ps aux | grep ksoftirqd root 3 0.0…